@natoe/colab 0.1.4 → 0.1.6
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.d.mts +16 -9
- package/dist/index.d.ts +16 -9
- package/dist/index.js +310 -115
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +311 -116
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React4, { createContext, forwardRef, useRef, useImperativeHandle, useEffect, useCallback, useState, useContext, useMemo } from 'react';
|
|
1
|
+
import React4, { createContext, forwardRef, useRef, useImperativeHandle, useEffect, useCallback, useState, useContext, useId, useMemo } from 'react';
|
|
2
2
|
import { Socket, Presence } from 'phoenix';
|
|
3
3
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
|
|
@@ -370,7 +370,9 @@ function CollabProvider({ config, apiBaseUrl, children }) {
|
|
|
370
370
|
const data = snakeToCamel(await response.json());
|
|
371
371
|
orderIds.forEach((orderId) => {
|
|
372
372
|
const preview = data.previews[orderId] ?? null;
|
|
373
|
-
|
|
373
|
+
if (preview !== null) {
|
|
374
|
+
previewCache.current.set(orderId, preview);
|
|
375
|
+
}
|
|
374
376
|
resolvers.get(orderId)?.forEach((resolve) => resolve(preview));
|
|
375
377
|
});
|
|
376
378
|
} catch (error) {
|
|
@@ -417,7 +419,8 @@ function CollabProvider({ config, apiBaseUrl, children }) {
|
|
|
417
419
|
if (!response.ok) {
|
|
418
420
|
throw { code: "FETCH_ERROR", message: "Failed to fetch messages", status: response.status };
|
|
419
421
|
}
|
|
420
|
-
|
|
422
|
+
const msgs = snakeToCamel(await response.json());
|
|
423
|
+
return msgs.sort((a, b) => a.insertedAt.localeCompare(b.insertedAt));
|
|
421
424
|
},
|
|
422
425
|
[apiBaseUrl, authHeaders]
|
|
423
426
|
);
|
|
@@ -891,8 +894,8 @@ function useConversation({
|
|
|
891
894
|
const payload = {
|
|
892
895
|
body: "Voice message",
|
|
893
896
|
type: "audio",
|
|
894
|
-
|
|
895
|
-
|
|
897
|
+
media_url: url,
|
|
898
|
+
media_duration: duration
|
|
896
899
|
};
|
|
897
900
|
const { conv, persistedByCreate } = await ensureConversation(payload);
|
|
898
901
|
if (persistedByCreate) return;
|
|
@@ -908,8 +911,8 @@ function useConversation({
|
|
|
908
911
|
const payload = {
|
|
909
912
|
body: file.name,
|
|
910
913
|
type: isImage ? "image" : "file",
|
|
911
|
-
|
|
912
|
-
|
|
914
|
+
media_url: url,
|
|
915
|
+
file_name: file.name
|
|
913
916
|
};
|
|
914
917
|
const { conv, persistedByCreate } = await ensureConversation(payload);
|
|
915
918
|
if (persistedByCreate) return;
|
|
@@ -1373,91 +1376,247 @@ var styles3 = {
|
|
|
1373
1376
|
textDecoration: "underline"
|
|
1374
1377
|
}
|
|
1375
1378
|
};
|
|
1379
|
+
function ReplyIcon({ size = 18, color = "currentColor" }) {
|
|
1380
|
+
return /* @__PURE__ */ jsx(
|
|
1381
|
+
"svg",
|
|
1382
|
+
{
|
|
1383
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1384
|
+
width: size,
|
|
1385
|
+
height: size,
|
|
1386
|
+
viewBox: "0 0 24 24",
|
|
1387
|
+
fill: color,
|
|
1388
|
+
"aria-hidden": "true",
|
|
1389
|
+
children: /* @__PURE__ */ jsx("path", { d: "M10 9V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z" })
|
|
1390
|
+
}
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
function PinIcon({ size = 14, color = "currentColor" }) {
|
|
1394
|
+
return /* @__PURE__ */ jsx(
|
|
1395
|
+
"svg",
|
|
1396
|
+
{
|
|
1397
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1398
|
+
width: size,
|
|
1399
|
+
height: size,
|
|
1400
|
+
viewBox: "0 0 24 24",
|
|
1401
|
+
fill: color,
|
|
1402
|
+
"aria-hidden": "true",
|
|
1403
|
+
children: /* @__PURE__ */ jsx("path", { d: "M16 9V4l1 0c.55 0 1-.45 1-1s-.45-1-1-1H7c-.55 0-1 .45-1 1s.45 1 1 1l1 0v5c0 1.66-1.34 3-3 3v2h5.97v7l1 1 1-1v-7H19v-2c-1.66 0-3-1.34-3-3z" })
|
|
1404
|
+
}
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
function CopyIcon({ size = 18, color = "currentColor" }) {
|
|
1408
|
+
return /* @__PURE__ */ jsx(
|
|
1409
|
+
"svg",
|
|
1410
|
+
{
|
|
1411
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1412
|
+
width: size,
|
|
1413
|
+
height: size,
|
|
1414
|
+
viewBox: "0 0 24 24",
|
|
1415
|
+
fill: color,
|
|
1416
|
+
"aria-hidden": "true",
|
|
1417
|
+
children: /* @__PURE__ */ jsx("path", { d: "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" })
|
|
1418
|
+
}
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
function MoreIcon({ size = 18, color = "currentColor" }) {
|
|
1422
|
+
return /* @__PURE__ */ jsxs(
|
|
1423
|
+
"svg",
|
|
1424
|
+
{
|
|
1425
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1426
|
+
width: size,
|
|
1427
|
+
height: size,
|
|
1428
|
+
viewBox: "0 0 24 24",
|
|
1429
|
+
fill: color,
|
|
1430
|
+
"aria-hidden": "true",
|
|
1431
|
+
children: [
|
|
1432
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "2" }),
|
|
1433
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "2" }),
|
|
1434
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "2" })
|
|
1435
|
+
]
|
|
1436
|
+
}
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1376
1439
|
function MessageActionsMenu({
|
|
1377
1440
|
message,
|
|
1378
1441
|
onReply,
|
|
1379
1442
|
onPin,
|
|
1380
1443
|
onUnpin,
|
|
1381
1444
|
onCopy,
|
|
1382
|
-
visible,
|
|
1383
1445
|
pinDisabled = false,
|
|
1446
|
+
anchorRight = false,
|
|
1384
1447
|
className
|
|
1385
1448
|
}) {
|
|
1386
|
-
|
|
1449
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1450
|
+
const wrapperRef = useRef(null);
|
|
1451
|
+
const triggerRef = useRef(null);
|
|
1387
1452
|
const isPinned = !!message.isPinned;
|
|
1388
1453
|
const canCopy = message.type === "text" && !!message.body;
|
|
1389
|
-
|
|
1390
|
-
if (!
|
|
1391
|
-
|
|
1454
|
+
useEffect(() => {
|
|
1455
|
+
if (!isOpen) return;
|
|
1456
|
+
const handleClick = (e) => {
|
|
1457
|
+
if (!wrapperRef.current?.contains(e.target)) {
|
|
1458
|
+
setIsOpen(false);
|
|
1459
|
+
}
|
|
1460
|
+
};
|
|
1461
|
+
const handleKey = (e) => {
|
|
1462
|
+
if (e.key === "Escape") {
|
|
1463
|
+
setIsOpen(false);
|
|
1464
|
+
triggerRef.current?.focus();
|
|
1465
|
+
}
|
|
1466
|
+
};
|
|
1467
|
+
document.addEventListener("mousedown", handleClick);
|
|
1468
|
+
document.addEventListener("keydown", handleKey);
|
|
1469
|
+
return () => {
|
|
1470
|
+
document.removeEventListener("mousedown", handleClick);
|
|
1471
|
+
document.removeEventListener("keydown", handleKey);
|
|
1472
|
+
};
|
|
1473
|
+
}, [isOpen]);
|
|
1474
|
+
const run = (fn) => {
|
|
1475
|
+
setIsOpen(false);
|
|
1476
|
+
fn();
|
|
1392
1477
|
};
|
|
1393
|
-
return /* @__PURE__ */ jsxs("div", { className, style: styles4.
|
|
1478
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapperRef, className, style: styles4.wrapper, children: [
|
|
1394
1479
|
/* @__PURE__ */ jsx(
|
|
1395
1480
|
"button",
|
|
1396
1481
|
{
|
|
1397
|
-
|
|
1398
|
-
style: styles4.button,
|
|
1399
|
-
title: "Reply",
|
|
1482
|
+
ref: triggerRef,
|
|
1400
1483
|
type: "button",
|
|
1401
|
-
|
|
1484
|
+
onClick: (e) => {
|
|
1485
|
+
e.stopPropagation();
|
|
1486
|
+
setIsOpen((v) => !v);
|
|
1487
|
+
},
|
|
1488
|
+
"aria-label": "Message actions",
|
|
1489
|
+
"aria-haspopup": "menu",
|
|
1490
|
+
"aria-expanded": isOpen ? "true" : "false",
|
|
1491
|
+
title: "Message actions",
|
|
1492
|
+
style: styles4.trigger,
|
|
1493
|
+
children: /* @__PURE__ */ jsx(MoreIcon, { size: 18, color: "#4b5563" })
|
|
1402
1494
|
}
|
|
1403
1495
|
),
|
|
1404
|
-
|
|
1405
|
-
"
|
|
1496
|
+
isOpen && /* @__PURE__ */ jsxs(
|
|
1497
|
+
"div",
|
|
1406
1498
|
{
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
title: "Unpin",
|
|
1410
|
-
type: "button",
|
|
1411
|
-
children: "\u{1F4CC}"
|
|
1412
|
-
}
|
|
1413
|
-
) : /* @__PURE__ */ jsx(
|
|
1414
|
-
"button",
|
|
1415
|
-
{
|
|
1416
|
-
onClick: () => onPin(message.id),
|
|
1499
|
+
role: "menu",
|
|
1500
|
+
"aria-label": "Message actions",
|
|
1417
1501
|
style: {
|
|
1418
|
-
...styles4.
|
|
1419
|
-
|
|
1420
|
-
cursor: pinDisabled ? "not-allowed" : "pointer"
|
|
1502
|
+
...styles4.menu,
|
|
1503
|
+
...anchorRight ? styles4.menuRight : styles4.menuLeft
|
|
1421
1504
|
},
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1505
|
+
children: [
|
|
1506
|
+
/* @__PURE__ */ jsxs(
|
|
1507
|
+
"button",
|
|
1508
|
+
{
|
|
1509
|
+
type: "button",
|
|
1510
|
+
role: "menuitem",
|
|
1511
|
+
onClick: () => run(() => onReply(message)),
|
|
1512
|
+
style: styles4.item,
|
|
1513
|
+
children: [
|
|
1514
|
+
/* @__PURE__ */ jsx(ReplyIcon, { size: 18, color: "#374151" }),
|
|
1515
|
+
/* @__PURE__ */ jsx("span", { children: "Reply" })
|
|
1516
|
+
]
|
|
1517
|
+
}
|
|
1518
|
+
),
|
|
1519
|
+
isPinned ? /* @__PURE__ */ jsxs(
|
|
1520
|
+
"button",
|
|
1521
|
+
{
|
|
1522
|
+
type: "button",
|
|
1523
|
+
role: "menuitem",
|
|
1524
|
+
onClick: () => run(() => onUnpin(message.id)),
|
|
1525
|
+
style: styles4.item,
|
|
1526
|
+
children: [
|
|
1527
|
+
/* @__PURE__ */ jsx(PinIcon, { size: 16, color: "#374151" }),
|
|
1528
|
+
/* @__PURE__ */ jsx("span", { children: "Unpin" })
|
|
1529
|
+
]
|
|
1530
|
+
}
|
|
1531
|
+
) : /* @__PURE__ */ jsxs(
|
|
1532
|
+
"button",
|
|
1533
|
+
{
|
|
1534
|
+
type: "button",
|
|
1535
|
+
role: "menuitem",
|
|
1536
|
+
onClick: () => run(() => onPin(message.id)),
|
|
1537
|
+
disabled: pinDisabled,
|
|
1538
|
+
style: {
|
|
1539
|
+
...styles4.item,
|
|
1540
|
+
...pinDisabled ? styles4.itemDisabled : {}
|
|
1541
|
+
},
|
|
1542
|
+
title: pinDisabled ? "Pin limit reached (max 3)" : void 0,
|
|
1543
|
+
children: [
|
|
1544
|
+
/* @__PURE__ */ jsx(PinIcon, { size: 16, color: "#374151" }),
|
|
1545
|
+
/* @__PURE__ */ jsx("span", { children: pinDisabled ? "Pin (limit reached)" : "Pin" })
|
|
1546
|
+
]
|
|
1547
|
+
}
|
|
1548
|
+
),
|
|
1549
|
+
canCopy && onCopy && /* @__PURE__ */ jsxs(
|
|
1550
|
+
"button",
|
|
1551
|
+
{
|
|
1552
|
+
type: "button",
|
|
1553
|
+
role: "menuitem",
|
|
1554
|
+
onClick: () => run(() => onCopy(message.body)),
|
|
1555
|
+
style: styles4.item,
|
|
1556
|
+
children: [
|
|
1557
|
+
/* @__PURE__ */ jsx(CopyIcon, { size: 16, color: "#374151" }),
|
|
1558
|
+
/* @__PURE__ */ jsx("span", { children: "Copy text" })
|
|
1559
|
+
]
|
|
1560
|
+
}
|
|
1561
|
+
)
|
|
1562
|
+
]
|
|
1436
1563
|
}
|
|
1437
1564
|
)
|
|
1438
1565
|
] });
|
|
1439
1566
|
}
|
|
1440
1567
|
var styles4 = {
|
|
1441
|
-
|
|
1568
|
+
wrapper: {
|
|
1569
|
+
position: "relative",
|
|
1570
|
+
display: "inline-block"
|
|
1571
|
+
},
|
|
1572
|
+
trigger: {
|
|
1573
|
+
width: "36px",
|
|
1574
|
+
height: "36px",
|
|
1442
1575
|
display: "flex",
|
|
1443
|
-
|
|
1444
|
-
|
|
1576
|
+
alignItems: "center",
|
|
1577
|
+
justifyContent: "center",
|
|
1578
|
+
backgroundColor: "transparent",
|
|
1579
|
+
border: "none",
|
|
1580
|
+
borderRadius: "50%",
|
|
1581
|
+
cursor: "pointer",
|
|
1582
|
+
color: "#4b5563"
|
|
1583
|
+
},
|
|
1584
|
+
menu: {
|
|
1585
|
+
position: "absolute",
|
|
1586
|
+
top: "100%",
|
|
1587
|
+
marginTop: "4px",
|
|
1588
|
+
minWidth: "160px",
|
|
1445
1589
|
backgroundColor: "#ffffff",
|
|
1446
1590
|
border: "1px solid #e5e7eb",
|
|
1447
|
-
borderRadius: "
|
|
1448
|
-
boxShadow: "0
|
|
1591
|
+
borderRadius: "10px",
|
|
1592
|
+
boxShadow: "0 6px 18px rgba(0, 0, 0, 0.12)",
|
|
1593
|
+
padding: "4px",
|
|
1594
|
+
zIndex: 20
|
|
1449
1595
|
},
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1596
|
+
menuLeft: {
|
|
1597
|
+
left: 0
|
|
1598
|
+
},
|
|
1599
|
+
menuRight: {
|
|
1600
|
+
right: 0
|
|
1601
|
+
},
|
|
1602
|
+
item: {
|
|
1453
1603
|
display: "flex",
|
|
1454
1604
|
alignItems: "center",
|
|
1455
|
-
|
|
1456
|
-
|
|
1605
|
+
gap: "10px",
|
|
1606
|
+
width: "100%",
|
|
1607
|
+
minHeight: "40px",
|
|
1608
|
+
padding: "8px 12px",
|
|
1609
|
+
fontSize: "14px",
|
|
1610
|
+
color: "#111827",
|
|
1457
1611
|
backgroundColor: "transparent",
|
|
1458
1612
|
border: "none",
|
|
1459
|
-
borderRadius: "
|
|
1460
|
-
cursor: "pointer"
|
|
1613
|
+
borderRadius: "6px",
|
|
1614
|
+
cursor: "pointer",
|
|
1615
|
+
textAlign: "left"
|
|
1616
|
+
},
|
|
1617
|
+
itemDisabled: {
|
|
1618
|
+
color: "#9ca3af",
|
|
1619
|
+
cursor: "not-allowed"
|
|
1461
1620
|
}
|
|
1462
1621
|
};
|
|
1463
1622
|
function FileIcon({ size = 18, color = "currentColor" }) {
|
|
@@ -1474,20 +1633,6 @@ function FileIcon({ size = 18, color = "currentColor" }) {
|
|
|
1474
1633
|
}
|
|
1475
1634
|
);
|
|
1476
1635
|
}
|
|
1477
|
-
function PinIcon({ size = 14, color = "currentColor" }) {
|
|
1478
|
-
return /* @__PURE__ */ jsx(
|
|
1479
|
-
"svg",
|
|
1480
|
-
{
|
|
1481
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
1482
|
-
width: size,
|
|
1483
|
-
height: size,
|
|
1484
|
-
viewBox: "0 0 24 24",
|
|
1485
|
-
fill: color,
|
|
1486
|
-
"aria-hidden": "true",
|
|
1487
|
-
children: /* @__PURE__ */ jsx("path", { d: "M16 9V4l1 0c.55 0 1-.45 1-1s-.45-1-1-1H7c-.55 0-1 .45-1 1s.45 1 1 1l1 0v5c0 1.66-1.34 3-3 3v2h5.97v7l1 1 1-1v-7H19v-2c-1.66 0-3-1.34-3-3z" })
|
|
1488
|
-
}
|
|
1489
|
-
);
|
|
1490
|
-
}
|
|
1491
1636
|
function AlertIcon({ size = 14, color = "currentColor" }) {
|
|
1492
1637
|
return /* @__PURE__ */ jsx(
|
|
1493
1638
|
"svg",
|
|
@@ -1552,12 +1697,26 @@ function MessageBubble({
|
|
|
1552
1697
|
pinDisabled = false,
|
|
1553
1698
|
className
|
|
1554
1699
|
}) {
|
|
1555
|
-
const [isHovered, setIsHovered] = useState(false);
|
|
1556
1700
|
if (message.type === "system") {
|
|
1557
1701
|
return /* @__PURE__ */ jsx(SystemBubble, { message });
|
|
1558
1702
|
}
|
|
1559
1703
|
const hasActions = !!(onReply || onPin || onUnpin || onCopy);
|
|
1560
|
-
|
|
1704
|
+
const actionsSlot = hasActions ? /* @__PURE__ */ jsx("div", { style: styles5.actionsSlot, children: /* @__PURE__ */ jsx(
|
|
1705
|
+
MessageActionsMenu,
|
|
1706
|
+
{
|
|
1707
|
+
message,
|
|
1708
|
+
onReply: onReply ?? (() => {
|
|
1709
|
+
}),
|
|
1710
|
+
onPin: onPin ?? (() => {
|
|
1711
|
+
}),
|
|
1712
|
+
onUnpin: onUnpin ?? (() => {
|
|
1713
|
+
}),
|
|
1714
|
+
onCopy,
|
|
1715
|
+
pinDisabled,
|
|
1716
|
+
anchorRight: !isOwn
|
|
1717
|
+
}
|
|
1718
|
+
) }) : null;
|
|
1719
|
+
return /* @__PURE__ */ jsxs(
|
|
1561
1720
|
"div",
|
|
1562
1721
|
{
|
|
1563
1722
|
className,
|
|
@@ -1565,10 +1724,9 @@ function MessageBubble({
|
|
|
1565
1724
|
...styles5.wrapper,
|
|
1566
1725
|
justifyContent: isOwn ? "flex-end" : "flex-start"
|
|
1567
1726
|
},
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
/* @__PURE__ */ jsxs(
|
|
1727
|
+
children: [
|
|
1728
|
+
isOwn && actionsSlot,
|
|
1729
|
+
/* @__PURE__ */ jsx("div", { style: styles5.bubbleWrapper, children: /* @__PURE__ */ jsxs(
|
|
1572
1730
|
"div",
|
|
1573
1731
|
{
|
|
1574
1732
|
style: {
|
|
@@ -1627,33 +1785,9 @@ function MessageBubble({
|
|
|
1627
1785
|
)
|
|
1628
1786
|
]
|
|
1629
1787
|
}
|
|
1630
|
-
),
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
{
|
|
1634
|
-
style: {
|
|
1635
|
-
...styles5.actionsWrapper,
|
|
1636
|
-
[isOwn ? "right" : "left"]: "100%",
|
|
1637
|
-
[isOwn ? "marginRight" : "marginLeft"]: "6px"
|
|
1638
|
-
},
|
|
1639
|
-
children: /* @__PURE__ */ jsx(
|
|
1640
|
-
MessageActionsMenu,
|
|
1641
|
-
{
|
|
1642
|
-
message,
|
|
1643
|
-
onReply: onReply ?? (() => {
|
|
1644
|
-
}),
|
|
1645
|
-
onPin: onPin ?? (() => {
|
|
1646
|
-
}),
|
|
1647
|
-
onUnpin: onUnpin ?? (() => {
|
|
1648
|
-
}),
|
|
1649
|
-
onCopy,
|
|
1650
|
-
visible: isHovered,
|
|
1651
|
-
pinDisabled
|
|
1652
|
-
}
|
|
1653
|
-
)
|
|
1654
|
-
}
|
|
1655
|
-
)
|
|
1656
|
-
] })
|
|
1788
|
+
) }),
|
|
1789
|
+
!isOwn && actionsSlot
|
|
1790
|
+
]
|
|
1657
1791
|
}
|
|
1658
1792
|
);
|
|
1659
1793
|
}
|
|
@@ -1750,6 +1884,8 @@ function escapeRegex2(string) {
|
|
|
1750
1884
|
var styles5 = {
|
|
1751
1885
|
wrapper: {
|
|
1752
1886
|
display: "flex",
|
|
1887
|
+
alignItems: "flex-end",
|
|
1888
|
+
gap: "4px",
|
|
1753
1889
|
marginBottom: "8px",
|
|
1754
1890
|
paddingLeft: "16px",
|
|
1755
1891
|
paddingRight: "16px"
|
|
@@ -1758,6 +1894,10 @@ var styles5 = {
|
|
|
1758
1894
|
position: "relative",
|
|
1759
1895
|
maxWidth: "75%"
|
|
1760
1896
|
},
|
|
1897
|
+
actionsSlot: {
|
|
1898
|
+
flexShrink: 0,
|
|
1899
|
+
alignSelf: "flex-end"
|
|
1900
|
+
},
|
|
1761
1901
|
bubble: {
|
|
1762
1902
|
padding: "10px 14px",
|
|
1763
1903
|
borderRadius: "12px",
|
|
@@ -1833,12 +1973,6 @@ var styles5 = {
|
|
|
1833
1973
|
cursor: "pointer",
|
|
1834
1974
|
padding: "0 2px"
|
|
1835
1975
|
},
|
|
1836
|
-
actionsWrapper: {
|
|
1837
|
-
position: "absolute",
|
|
1838
|
-
top: "50%",
|
|
1839
|
-
transform: "translateY(-50%)",
|
|
1840
|
-
zIndex: 10
|
|
1841
|
-
},
|
|
1842
1976
|
audioContainer: {
|
|
1843
1977
|
display: "flex",
|
|
1844
1978
|
alignItems: "center",
|
|
@@ -2488,7 +2622,18 @@ function MessageInput({
|
|
|
2488
2622
|
type: "file",
|
|
2489
2623
|
onChange: handleFileSelect,
|
|
2490
2624
|
style: { display: "none" },
|
|
2491
|
-
accept: [
|
|
2625
|
+
accept: [
|
|
2626
|
+
...SUPPORTED_IMAGE_TYPES,
|
|
2627
|
+
"application/pdf",
|
|
2628
|
+
".doc",
|
|
2629
|
+
".docx",
|
|
2630
|
+
".xls",
|
|
2631
|
+
".xlsx",
|
|
2632
|
+
".csv",
|
|
2633
|
+
".txt",
|
|
2634
|
+
".heic",
|
|
2635
|
+
".heif"
|
|
2636
|
+
].join(",")
|
|
2492
2637
|
}
|
|
2493
2638
|
),
|
|
2494
2639
|
/* @__PURE__ */ jsx(
|
|
@@ -3500,12 +3645,14 @@ function ExpandIcon({ size = 18, color = "currentColor" }) {
|
|
|
3500
3645
|
}
|
|
3501
3646
|
);
|
|
3502
3647
|
}
|
|
3648
|
+
var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
3503
3649
|
function CollabPopup({
|
|
3504
3650
|
orderId,
|
|
3505
3651
|
patientData,
|
|
3506
3652
|
participantIds,
|
|
3507
3653
|
isOpen,
|
|
3508
3654
|
onClose,
|
|
3655
|
+
onBack,
|
|
3509
3656
|
initialPosition,
|
|
3510
3657
|
width = 380,
|
|
3511
3658
|
height = 520,
|
|
@@ -3521,6 +3668,8 @@ function CollabPopup({
|
|
|
3521
3668
|
const [isMinimized, setIsMinimized] = useState(false);
|
|
3522
3669
|
const dragOffset = useRef({ x: 0, y: 0 });
|
|
3523
3670
|
const containerRef = useRef(null);
|
|
3671
|
+
const previouslyFocused = useRef(null);
|
|
3672
|
+
const titleId = useId();
|
|
3524
3673
|
const handleMouseDown = useCallback(
|
|
3525
3674
|
(e) => {
|
|
3526
3675
|
if (!e.target.closest("[data-drag-handle]")) return;
|
|
@@ -3535,13 +3684,44 @@ function CollabPopup({
|
|
|
3535
3684
|
);
|
|
3536
3685
|
useEffect(() => {
|
|
3537
3686
|
if (!isOpen) return;
|
|
3687
|
+
previouslyFocused.current = document.activeElement;
|
|
3688
|
+
const focusFirst = () => {
|
|
3689
|
+
const root = containerRef.current;
|
|
3690
|
+
if (!root) return;
|
|
3691
|
+
const first = root.querySelector(FOCUSABLE_SELECTOR);
|
|
3692
|
+
(first ?? root).focus();
|
|
3693
|
+
};
|
|
3694
|
+
const raf = requestAnimationFrame(focusFirst);
|
|
3538
3695
|
const handleKey = (e) => {
|
|
3539
3696
|
if (e.key === "Escape") {
|
|
3540
3697
|
onClose();
|
|
3698
|
+
return;
|
|
3699
|
+
}
|
|
3700
|
+
if (e.key !== "Tab") return;
|
|
3701
|
+
const root = containerRef.current;
|
|
3702
|
+
if (!root) return;
|
|
3703
|
+
const focusables = Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
3704
|
+
if (focusables.length === 0) {
|
|
3705
|
+
e.preventDefault();
|
|
3706
|
+
return;
|
|
3707
|
+
}
|
|
3708
|
+
const first = focusables[0];
|
|
3709
|
+
const last = focusables[focusables.length - 1];
|
|
3710
|
+
const active = document.activeElement;
|
|
3711
|
+
if (e.shiftKey && active === first) {
|
|
3712
|
+
e.preventDefault();
|
|
3713
|
+
last.focus();
|
|
3714
|
+
} else if (!e.shiftKey && active === last) {
|
|
3715
|
+
e.preventDefault();
|
|
3716
|
+
first.focus();
|
|
3541
3717
|
}
|
|
3542
3718
|
};
|
|
3543
3719
|
window.addEventListener("keydown", handleKey);
|
|
3544
|
-
return () =>
|
|
3720
|
+
return () => {
|
|
3721
|
+
cancelAnimationFrame(raf);
|
|
3722
|
+
window.removeEventListener("keydown", handleKey);
|
|
3723
|
+
previouslyFocused.current?.focus?.();
|
|
3724
|
+
};
|
|
3545
3725
|
}, [isOpen, onClose]);
|
|
3546
3726
|
useEffect(() => {
|
|
3547
3727
|
if (!isDragging) return;
|
|
@@ -3567,6 +3747,10 @@ function CollabPopup({
|
|
|
3567
3747
|
{
|
|
3568
3748
|
ref: containerRef,
|
|
3569
3749
|
className,
|
|
3750
|
+
role: "dialog",
|
|
3751
|
+
"aria-modal": "true",
|
|
3752
|
+
"aria-labelledby": titleId,
|
|
3753
|
+
tabIndex: -1,
|
|
3570
3754
|
style: {
|
|
3571
3755
|
...styles13.container,
|
|
3572
3756
|
left: position.x,
|
|
@@ -3578,7 +3762,18 @@ function CollabPopup({
|
|
|
3578
3762
|
onMouseDown: handleMouseDown,
|
|
3579
3763
|
children: [
|
|
3580
3764
|
/* @__PURE__ */ jsxs("div", { "data-drag-handle": true, style: styles13.titleBar, children: [
|
|
3581
|
-
/* @__PURE__ */ jsx(
|
|
3765
|
+
onBack && /* @__PURE__ */ jsx(
|
|
3766
|
+
"button",
|
|
3767
|
+
{
|
|
3768
|
+
onClick: onBack,
|
|
3769
|
+
style: styles13.titleButton,
|
|
3770
|
+
"aria-label": "Go back",
|
|
3771
|
+
title: "Back",
|
|
3772
|
+
type: "button",
|
|
3773
|
+
children: "\u2190"
|
|
3774
|
+
}
|
|
3775
|
+
),
|
|
3776
|
+
/* @__PURE__ */ jsx("span", { id: titleId, style: { ...styles13.titleText, flex: 1 }, children: buildChannelName(patientData) }),
|
|
3582
3777
|
/* @__PURE__ */ jsxs("div", { style: styles13.titleActions, children: [
|
|
3583
3778
|
/* @__PURE__ */ jsx(
|
|
3584
3779
|
"button",
|
|
@@ -3865,8 +4060,8 @@ function useInlineCollab({
|
|
|
3865
4060
|
await dispatchSend({
|
|
3866
4061
|
body: "Voice message",
|
|
3867
4062
|
type: "audio",
|
|
3868
|
-
|
|
3869
|
-
|
|
4063
|
+
media_url: url,
|
|
4064
|
+
media_duration: duration
|
|
3870
4065
|
});
|
|
3871
4066
|
} catch (err) {
|
|
3872
4067
|
setError(err instanceof Error ? err.message : "Failed to send voice message");
|