@natoe/colab 0.1.4 → 0.1.5
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 +10 -5
- package/dist/index.d.ts +10 -5
- package/dist/index.js +287 -107
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +288 -108
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -734,17 +734,22 @@ interface MessageActionsMenuProps {
|
|
|
734
734
|
onPin: (messageId: string) => void;
|
|
735
735
|
onUnpin: (messageId: string) => void;
|
|
736
736
|
onCopy?: (text: string) => void;
|
|
737
|
-
/** True when the menu should show (hover / open state managed by parent) */
|
|
738
|
-
visible: boolean;
|
|
739
737
|
/** Whether we've hit the pin limit — if true, pin is disabled */
|
|
740
738
|
pinDisabled?: boolean;
|
|
739
|
+
/** Anchor the popover to the left of the trigger (use for own bubbles) */
|
|
740
|
+
anchorRight?: boolean;
|
|
741
741
|
className?: string;
|
|
742
742
|
}
|
|
743
743
|
/**
|
|
744
|
-
*
|
|
745
|
-
*
|
|
744
|
+
* Self-contained "⋯" trigger + popover for per-message actions. Replaces
|
|
745
|
+
* the previous hover-only floating menu so touch users (and anyone with
|
|
746
|
+
* a non-pointer device) can reach Reply / Pin / Copy.
|
|
747
|
+
*
|
|
748
|
+
* Menu rows are icon + text so the affordance reads cold; the trigger is
|
|
749
|
+
* a 36px tap target. Closes on outside-click, Escape, or after selecting
|
|
750
|
+
* an action.
|
|
746
751
|
*/
|
|
747
|
-
declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy,
|
|
752
|
+
declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
|
|
748
753
|
|
|
749
754
|
interface ReplyPreviewProps {
|
|
750
755
|
/** The message being replied to */
|
package/dist/index.d.ts
CHANGED
|
@@ -734,17 +734,22 @@ interface MessageActionsMenuProps {
|
|
|
734
734
|
onPin: (messageId: string) => void;
|
|
735
735
|
onUnpin: (messageId: string) => void;
|
|
736
736
|
onCopy?: (text: string) => void;
|
|
737
|
-
/** True when the menu should show (hover / open state managed by parent) */
|
|
738
|
-
visible: boolean;
|
|
739
737
|
/** Whether we've hit the pin limit — if true, pin is disabled */
|
|
740
738
|
pinDisabled?: boolean;
|
|
739
|
+
/** Anchor the popover to the left of the trigger (use for own bubbles) */
|
|
740
|
+
anchorRight?: boolean;
|
|
741
741
|
className?: string;
|
|
742
742
|
}
|
|
743
743
|
/**
|
|
744
|
-
*
|
|
745
|
-
*
|
|
744
|
+
* Self-contained "⋯" trigger + popover for per-message actions. Replaces
|
|
745
|
+
* the previous hover-only floating menu so touch users (and anyone with
|
|
746
|
+
* a non-pointer device) can reach Reply / Pin / Copy.
|
|
747
|
+
*
|
|
748
|
+
* Menu rows are icon + text so the affordance reads cold; the trigger is
|
|
749
|
+
* a 36px tap target. Closes on outside-click, Escape, or after selecting
|
|
750
|
+
* an action.
|
|
746
751
|
*/
|
|
747
|
-
declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy,
|
|
752
|
+
declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
|
|
748
753
|
|
|
749
754
|
interface ReplyPreviewProps {
|
|
750
755
|
/** The message being replied to */
|
package/dist/index.js
CHANGED
|
@@ -1379,91 +1379,247 @@ var styles3 = {
|
|
|
1379
1379
|
textDecoration: "underline"
|
|
1380
1380
|
}
|
|
1381
1381
|
};
|
|
1382
|
+
function ReplyIcon({ size = 18, color = "currentColor" }) {
|
|
1383
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1384
|
+
"svg",
|
|
1385
|
+
{
|
|
1386
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1387
|
+
width: size,
|
|
1388
|
+
height: size,
|
|
1389
|
+
viewBox: "0 0 24 24",
|
|
1390
|
+
fill: color,
|
|
1391
|
+
"aria-hidden": "true",
|
|
1392
|
+
children: /* @__PURE__ */ jsxRuntime.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" })
|
|
1393
|
+
}
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
function PinIcon({ size = 14, color = "currentColor" }) {
|
|
1397
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1398
|
+
"svg",
|
|
1399
|
+
{
|
|
1400
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1401
|
+
width: size,
|
|
1402
|
+
height: size,
|
|
1403
|
+
viewBox: "0 0 24 24",
|
|
1404
|
+
fill: color,
|
|
1405
|
+
"aria-hidden": "true",
|
|
1406
|
+
children: /* @__PURE__ */ jsxRuntime.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" })
|
|
1407
|
+
}
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
function CopyIcon({ size = 18, color = "currentColor" }) {
|
|
1411
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1412
|
+
"svg",
|
|
1413
|
+
{
|
|
1414
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1415
|
+
width: size,
|
|
1416
|
+
height: size,
|
|
1417
|
+
viewBox: "0 0 24 24",
|
|
1418
|
+
fill: color,
|
|
1419
|
+
"aria-hidden": "true",
|
|
1420
|
+
children: /* @__PURE__ */ jsxRuntime.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" })
|
|
1421
|
+
}
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
function MoreIcon({ size = 18, color = "currentColor" }) {
|
|
1425
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1426
|
+
"svg",
|
|
1427
|
+
{
|
|
1428
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1429
|
+
width: size,
|
|
1430
|
+
height: size,
|
|
1431
|
+
viewBox: "0 0 24 24",
|
|
1432
|
+
fill: color,
|
|
1433
|
+
"aria-hidden": "true",
|
|
1434
|
+
children: [
|
|
1435
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "5", r: "2" }),
|
|
1436
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "2" }),
|
|
1437
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "19", r: "2" })
|
|
1438
|
+
]
|
|
1439
|
+
}
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1382
1442
|
function MessageActionsMenu({
|
|
1383
1443
|
message,
|
|
1384
1444
|
onReply,
|
|
1385
1445
|
onPin,
|
|
1386
1446
|
onUnpin,
|
|
1387
1447
|
onCopy,
|
|
1388
|
-
visible,
|
|
1389
1448
|
pinDisabled = false,
|
|
1449
|
+
anchorRight = false,
|
|
1390
1450
|
className
|
|
1391
1451
|
}) {
|
|
1392
|
-
|
|
1452
|
+
const [isOpen, setIsOpen] = React4.useState(false);
|
|
1453
|
+
const wrapperRef = React4.useRef(null);
|
|
1454
|
+
const triggerRef = React4.useRef(null);
|
|
1393
1455
|
const isPinned = !!message.isPinned;
|
|
1394
1456
|
const canCopy = message.type === "text" && !!message.body;
|
|
1395
|
-
|
|
1396
|
-
if (!
|
|
1397
|
-
|
|
1457
|
+
React4.useEffect(() => {
|
|
1458
|
+
if (!isOpen) return;
|
|
1459
|
+
const handleClick = (e) => {
|
|
1460
|
+
if (!wrapperRef.current?.contains(e.target)) {
|
|
1461
|
+
setIsOpen(false);
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
const handleKey = (e) => {
|
|
1465
|
+
if (e.key === "Escape") {
|
|
1466
|
+
setIsOpen(false);
|
|
1467
|
+
triggerRef.current?.focus();
|
|
1468
|
+
}
|
|
1469
|
+
};
|
|
1470
|
+
document.addEventListener("mousedown", handleClick);
|
|
1471
|
+
document.addEventListener("keydown", handleKey);
|
|
1472
|
+
return () => {
|
|
1473
|
+
document.removeEventListener("mousedown", handleClick);
|
|
1474
|
+
document.removeEventListener("keydown", handleKey);
|
|
1475
|
+
};
|
|
1476
|
+
}, [isOpen]);
|
|
1477
|
+
const run = (fn) => {
|
|
1478
|
+
setIsOpen(false);
|
|
1479
|
+
fn();
|
|
1398
1480
|
};
|
|
1399
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: styles4.
|
|
1481
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapperRef, className, style: styles4.wrapper, children: [
|
|
1400
1482
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1401
1483
|
"button",
|
|
1402
1484
|
{
|
|
1403
|
-
|
|
1404
|
-
style: styles4.button,
|
|
1405
|
-
title: "Reply",
|
|
1485
|
+
ref: triggerRef,
|
|
1406
1486
|
type: "button",
|
|
1407
|
-
|
|
1487
|
+
onClick: (e) => {
|
|
1488
|
+
e.stopPropagation();
|
|
1489
|
+
setIsOpen((v) => !v);
|
|
1490
|
+
},
|
|
1491
|
+
"aria-label": "Message actions",
|
|
1492
|
+
"aria-haspopup": "menu",
|
|
1493
|
+
"aria-expanded": isOpen ? "true" : "false",
|
|
1494
|
+
title: "Message actions",
|
|
1495
|
+
style: styles4.trigger,
|
|
1496
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(MoreIcon, { size: 18, color: "#4b5563" })
|
|
1408
1497
|
}
|
|
1409
1498
|
),
|
|
1410
|
-
|
|
1411
|
-
"
|
|
1412
|
-
{
|
|
1413
|
-
onClick: () => onUnpin(message.id),
|
|
1414
|
-
style: styles4.button,
|
|
1415
|
-
title: "Unpin",
|
|
1416
|
-
type: "button",
|
|
1417
|
-
children: "\u{1F4CC}"
|
|
1418
|
-
}
|
|
1419
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1420
|
-
"button",
|
|
1499
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1500
|
+
"div",
|
|
1421
1501
|
{
|
|
1422
|
-
|
|
1502
|
+
role: "menu",
|
|
1503
|
+
"aria-label": "Message actions",
|
|
1423
1504
|
style: {
|
|
1424
|
-
...styles4.
|
|
1425
|
-
|
|
1426
|
-
cursor: pinDisabled ? "not-allowed" : "pointer"
|
|
1505
|
+
...styles4.menu,
|
|
1506
|
+
...anchorRight ? styles4.menuRight : styles4.menuLeft
|
|
1427
1507
|
},
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1508
|
+
children: [
|
|
1509
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1510
|
+
"button",
|
|
1511
|
+
{
|
|
1512
|
+
type: "button",
|
|
1513
|
+
role: "menuitem",
|
|
1514
|
+
onClick: () => run(() => onReply(message)),
|
|
1515
|
+
style: styles4.item,
|
|
1516
|
+
children: [
|
|
1517
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReplyIcon, { size: 18, color: "#374151" }),
|
|
1518
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Reply" })
|
|
1519
|
+
]
|
|
1520
|
+
}
|
|
1521
|
+
),
|
|
1522
|
+
isPinned ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1523
|
+
"button",
|
|
1524
|
+
{
|
|
1525
|
+
type: "button",
|
|
1526
|
+
role: "menuitem",
|
|
1527
|
+
onClick: () => run(() => onUnpin(message.id)),
|
|
1528
|
+
style: styles4.item,
|
|
1529
|
+
children: [
|
|
1530
|
+
/* @__PURE__ */ jsxRuntime.jsx(PinIcon, { size: 16, color: "#374151" }),
|
|
1531
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Unpin" })
|
|
1532
|
+
]
|
|
1533
|
+
}
|
|
1534
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1535
|
+
"button",
|
|
1536
|
+
{
|
|
1537
|
+
type: "button",
|
|
1538
|
+
role: "menuitem",
|
|
1539
|
+
onClick: () => run(() => onPin(message.id)),
|
|
1540
|
+
disabled: pinDisabled,
|
|
1541
|
+
style: {
|
|
1542
|
+
...styles4.item,
|
|
1543
|
+
...pinDisabled ? styles4.itemDisabled : {}
|
|
1544
|
+
},
|
|
1545
|
+
title: pinDisabled ? "Pin limit reached (max 3)" : void 0,
|
|
1546
|
+
children: [
|
|
1547
|
+
/* @__PURE__ */ jsxRuntime.jsx(PinIcon, { size: 16, color: "#374151" }),
|
|
1548
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: pinDisabled ? "Pin (limit reached)" : "Pin" })
|
|
1549
|
+
]
|
|
1550
|
+
}
|
|
1551
|
+
),
|
|
1552
|
+
canCopy && onCopy && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1553
|
+
"button",
|
|
1554
|
+
{
|
|
1555
|
+
type: "button",
|
|
1556
|
+
role: "menuitem",
|
|
1557
|
+
onClick: () => run(() => onCopy(message.body)),
|
|
1558
|
+
style: styles4.item,
|
|
1559
|
+
children: [
|
|
1560
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyIcon, { size: 16, color: "#374151" }),
|
|
1561
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Copy text" })
|
|
1562
|
+
]
|
|
1563
|
+
}
|
|
1564
|
+
)
|
|
1565
|
+
]
|
|
1442
1566
|
}
|
|
1443
1567
|
)
|
|
1444
1568
|
] });
|
|
1445
1569
|
}
|
|
1446
1570
|
var styles4 = {
|
|
1447
|
-
|
|
1571
|
+
wrapper: {
|
|
1572
|
+
position: "relative",
|
|
1573
|
+
display: "inline-block"
|
|
1574
|
+
},
|
|
1575
|
+
trigger: {
|
|
1576
|
+
width: "36px",
|
|
1577
|
+
height: "36px",
|
|
1448
1578
|
display: "flex",
|
|
1449
|
-
|
|
1450
|
-
|
|
1579
|
+
alignItems: "center",
|
|
1580
|
+
justifyContent: "center",
|
|
1581
|
+
backgroundColor: "transparent",
|
|
1582
|
+
border: "none",
|
|
1583
|
+
borderRadius: "50%",
|
|
1584
|
+
cursor: "pointer",
|
|
1585
|
+
color: "#4b5563"
|
|
1586
|
+
},
|
|
1587
|
+
menu: {
|
|
1588
|
+
position: "absolute",
|
|
1589
|
+
top: "100%",
|
|
1590
|
+
marginTop: "4px",
|
|
1591
|
+
minWidth: "160px",
|
|
1451
1592
|
backgroundColor: "#ffffff",
|
|
1452
1593
|
border: "1px solid #e5e7eb",
|
|
1453
|
-
borderRadius: "
|
|
1454
|
-
boxShadow: "0
|
|
1594
|
+
borderRadius: "10px",
|
|
1595
|
+
boxShadow: "0 6px 18px rgba(0, 0, 0, 0.12)",
|
|
1596
|
+
padding: "4px",
|
|
1597
|
+
zIndex: 20
|
|
1455
1598
|
},
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1599
|
+
menuLeft: {
|
|
1600
|
+
left: 0
|
|
1601
|
+
},
|
|
1602
|
+
menuRight: {
|
|
1603
|
+
right: 0
|
|
1604
|
+
},
|
|
1605
|
+
item: {
|
|
1459
1606
|
display: "flex",
|
|
1460
1607
|
alignItems: "center",
|
|
1461
|
-
|
|
1462
|
-
|
|
1608
|
+
gap: "10px",
|
|
1609
|
+
width: "100%",
|
|
1610
|
+
minHeight: "40px",
|
|
1611
|
+
padding: "8px 12px",
|
|
1612
|
+
fontSize: "14px",
|
|
1613
|
+
color: "#111827",
|
|
1463
1614
|
backgroundColor: "transparent",
|
|
1464
1615
|
border: "none",
|
|
1465
|
-
borderRadius: "
|
|
1466
|
-
cursor: "pointer"
|
|
1616
|
+
borderRadius: "6px",
|
|
1617
|
+
cursor: "pointer",
|
|
1618
|
+
textAlign: "left"
|
|
1619
|
+
},
|
|
1620
|
+
itemDisabled: {
|
|
1621
|
+
color: "#9ca3af",
|
|
1622
|
+
cursor: "not-allowed"
|
|
1467
1623
|
}
|
|
1468
1624
|
};
|
|
1469
1625
|
function FileIcon({ size = 18, color = "currentColor" }) {
|
|
@@ -1480,20 +1636,6 @@ function FileIcon({ size = 18, color = "currentColor" }) {
|
|
|
1480
1636
|
}
|
|
1481
1637
|
);
|
|
1482
1638
|
}
|
|
1483
|
-
function PinIcon({ size = 14, color = "currentColor" }) {
|
|
1484
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1485
|
-
"svg",
|
|
1486
|
-
{
|
|
1487
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
1488
|
-
width: size,
|
|
1489
|
-
height: size,
|
|
1490
|
-
viewBox: "0 0 24 24",
|
|
1491
|
-
fill: color,
|
|
1492
|
-
"aria-hidden": "true",
|
|
1493
|
-
children: /* @__PURE__ */ jsxRuntime.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" })
|
|
1494
|
-
}
|
|
1495
|
-
);
|
|
1496
|
-
}
|
|
1497
1639
|
function AlertIcon({ size = 14, color = "currentColor" }) {
|
|
1498
1640
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1499
1641
|
"svg",
|
|
@@ -1558,12 +1700,26 @@ function MessageBubble({
|
|
|
1558
1700
|
pinDisabled = false,
|
|
1559
1701
|
className
|
|
1560
1702
|
}) {
|
|
1561
|
-
const [isHovered, setIsHovered] = React4.useState(false);
|
|
1562
1703
|
if (message.type === "system") {
|
|
1563
1704
|
return /* @__PURE__ */ jsxRuntime.jsx(SystemBubble, { message });
|
|
1564
1705
|
}
|
|
1565
1706
|
const hasActions = !!(onReply || onPin || onUnpin || onCopy);
|
|
1566
|
-
|
|
1707
|
+
const actionsSlot = hasActions ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.actionsSlot, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1708
|
+
MessageActionsMenu,
|
|
1709
|
+
{
|
|
1710
|
+
message,
|
|
1711
|
+
onReply: onReply ?? (() => {
|
|
1712
|
+
}),
|
|
1713
|
+
onPin: onPin ?? (() => {
|
|
1714
|
+
}),
|
|
1715
|
+
onUnpin: onUnpin ?? (() => {
|
|
1716
|
+
}),
|
|
1717
|
+
onCopy,
|
|
1718
|
+
pinDisabled,
|
|
1719
|
+
anchorRight: !isOwn
|
|
1720
|
+
}
|
|
1721
|
+
) }) : null;
|
|
1722
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1567
1723
|
"div",
|
|
1568
1724
|
{
|
|
1569
1725
|
className,
|
|
@@ -1571,10 +1727,9 @@ function MessageBubble({
|
|
|
1571
1727
|
...styles5.wrapper,
|
|
1572
1728
|
justifyContent: isOwn ? "flex-end" : "flex-start"
|
|
1573
1729
|
},
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1730
|
+
children: [
|
|
1731
|
+
isOwn && actionsSlot,
|
|
1732
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.bubbleWrapper, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1578
1733
|
"div",
|
|
1579
1734
|
{
|
|
1580
1735
|
style: {
|
|
@@ -1633,33 +1788,9 @@ function MessageBubble({
|
|
|
1633
1788
|
)
|
|
1634
1789
|
]
|
|
1635
1790
|
}
|
|
1636
|
-
),
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
{
|
|
1640
|
-
style: {
|
|
1641
|
-
...styles5.actionsWrapper,
|
|
1642
|
-
[isOwn ? "right" : "left"]: "100%",
|
|
1643
|
-
[isOwn ? "marginRight" : "marginLeft"]: "6px"
|
|
1644
|
-
},
|
|
1645
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1646
|
-
MessageActionsMenu,
|
|
1647
|
-
{
|
|
1648
|
-
message,
|
|
1649
|
-
onReply: onReply ?? (() => {
|
|
1650
|
-
}),
|
|
1651
|
-
onPin: onPin ?? (() => {
|
|
1652
|
-
}),
|
|
1653
|
-
onUnpin: onUnpin ?? (() => {
|
|
1654
|
-
}),
|
|
1655
|
-
onCopy,
|
|
1656
|
-
visible: isHovered,
|
|
1657
|
-
pinDisabled
|
|
1658
|
-
}
|
|
1659
|
-
)
|
|
1660
|
-
}
|
|
1661
|
-
)
|
|
1662
|
-
] })
|
|
1791
|
+
) }),
|
|
1792
|
+
!isOwn && actionsSlot
|
|
1793
|
+
]
|
|
1663
1794
|
}
|
|
1664
1795
|
);
|
|
1665
1796
|
}
|
|
@@ -1756,6 +1887,8 @@ function escapeRegex2(string) {
|
|
|
1756
1887
|
var styles5 = {
|
|
1757
1888
|
wrapper: {
|
|
1758
1889
|
display: "flex",
|
|
1890
|
+
alignItems: "flex-end",
|
|
1891
|
+
gap: "4px",
|
|
1759
1892
|
marginBottom: "8px",
|
|
1760
1893
|
paddingLeft: "16px",
|
|
1761
1894
|
paddingRight: "16px"
|
|
@@ -1764,6 +1897,10 @@ var styles5 = {
|
|
|
1764
1897
|
position: "relative",
|
|
1765
1898
|
maxWidth: "75%"
|
|
1766
1899
|
},
|
|
1900
|
+
actionsSlot: {
|
|
1901
|
+
flexShrink: 0,
|
|
1902
|
+
alignSelf: "flex-end"
|
|
1903
|
+
},
|
|
1767
1904
|
bubble: {
|
|
1768
1905
|
padding: "10px 14px",
|
|
1769
1906
|
borderRadius: "12px",
|
|
@@ -1839,12 +1976,6 @@ var styles5 = {
|
|
|
1839
1976
|
cursor: "pointer",
|
|
1840
1977
|
padding: "0 2px"
|
|
1841
1978
|
},
|
|
1842
|
-
actionsWrapper: {
|
|
1843
|
-
position: "absolute",
|
|
1844
|
-
top: "50%",
|
|
1845
|
-
transform: "translateY(-50%)",
|
|
1846
|
-
zIndex: 10
|
|
1847
|
-
},
|
|
1848
1979
|
audioContainer: {
|
|
1849
1980
|
display: "flex",
|
|
1850
1981
|
alignItems: "center",
|
|
@@ -2494,7 +2625,18 @@ function MessageInput({
|
|
|
2494
2625
|
type: "file",
|
|
2495
2626
|
onChange: handleFileSelect,
|
|
2496
2627
|
style: { display: "none" },
|
|
2497
|
-
accept: [
|
|
2628
|
+
accept: [
|
|
2629
|
+
...SUPPORTED_IMAGE_TYPES,
|
|
2630
|
+
"application/pdf",
|
|
2631
|
+
".doc",
|
|
2632
|
+
".docx",
|
|
2633
|
+
".xls",
|
|
2634
|
+
".xlsx",
|
|
2635
|
+
".csv",
|
|
2636
|
+
".txt",
|
|
2637
|
+
".heic",
|
|
2638
|
+
".heif"
|
|
2639
|
+
].join(",")
|
|
2498
2640
|
}
|
|
2499
2641
|
),
|
|
2500
2642
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3506,6 +3648,7 @@ function ExpandIcon({ size = 18, color = "currentColor" }) {
|
|
|
3506
3648
|
}
|
|
3507
3649
|
);
|
|
3508
3650
|
}
|
|
3651
|
+
var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
3509
3652
|
function CollabPopup({
|
|
3510
3653
|
orderId,
|
|
3511
3654
|
patientData,
|
|
@@ -3527,6 +3670,8 @@ function CollabPopup({
|
|
|
3527
3670
|
const [isMinimized, setIsMinimized] = React4.useState(false);
|
|
3528
3671
|
const dragOffset = React4.useRef({ x: 0, y: 0 });
|
|
3529
3672
|
const containerRef = React4.useRef(null);
|
|
3673
|
+
const previouslyFocused = React4.useRef(null);
|
|
3674
|
+
const titleId = React4.useId();
|
|
3530
3675
|
const handleMouseDown = React4.useCallback(
|
|
3531
3676
|
(e) => {
|
|
3532
3677
|
if (!e.target.closest("[data-drag-handle]")) return;
|
|
@@ -3541,13 +3686,44 @@ function CollabPopup({
|
|
|
3541
3686
|
);
|
|
3542
3687
|
React4.useEffect(() => {
|
|
3543
3688
|
if (!isOpen) return;
|
|
3689
|
+
previouslyFocused.current = document.activeElement;
|
|
3690
|
+
const focusFirst = () => {
|
|
3691
|
+
const root = containerRef.current;
|
|
3692
|
+
if (!root) return;
|
|
3693
|
+
const first = root.querySelector(FOCUSABLE_SELECTOR);
|
|
3694
|
+
(first ?? root).focus();
|
|
3695
|
+
};
|
|
3696
|
+
const raf = requestAnimationFrame(focusFirst);
|
|
3544
3697
|
const handleKey = (e) => {
|
|
3545
3698
|
if (e.key === "Escape") {
|
|
3546
3699
|
onClose();
|
|
3700
|
+
return;
|
|
3701
|
+
}
|
|
3702
|
+
if (e.key !== "Tab") return;
|
|
3703
|
+
const root = containerRef.current;
|
|
3704
|
+
if (!root) return;
|
|
3705
|
+
const focusables = Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
3706
|
+
if (focusables.length === 0) {
|
|
3707
|
+
e.preventDefault();
|
|
3708
|
+
return;
|
|
3709
|
+
}
|
|
3710
|
+
const first = focusables[0];
|
|
3711
|
+
const last = focusables[focusables.length - 1];
|
|
3712
|
+
const active = document.activeElement;
|
|
3713
|
+
if (e.shiftKey && active === first) {
|
|
3714
|
+
e.preventDefault();
|
|
3715
|
+
last.focus();
|
|
3716
|
+
} else if (!e.shiftKey && active === last) {
|
|
3717
|
+
e.preventDefault();
|
|
3718
|
+
first.focus();
|
|
3547
3719
|
}
|
|
3548
3720
|
};
|
|
3549
3721
|
window.addEventListener("keydown", handleKey);
|
|
3550
|
-
return () =>
|
|
3722
|
+
return () => {
|
|
3723
|
+
cancelAnimationFrame(raf);
|
|
3724
|
+
window.removeEventListener("keydown", handleKey);
|
|
3725
|
+
previouslyFocused.current?.focus?.();
|
|
3726
|
+
};
|
|
3551
3727
|
}, [isOpen, onClose]);
|
|
3552
3728
|
React4.useEffect(() => {
|
|
3553
3729
|
if (!isDragging) return;
|
|
@@ -3573,6 +3749,10 @@ function CollabPopup({
|
|
|
3573
3749
|
{
|
|
3574
3750
|
ref: containerRef,
|
|
3575
3751
|
className,
|
|
3752
|
+
role: "dialog",
|
|
3753
|
+
"aria-modal": "true",
|
|
3754
|
+
"aria-labelledby": titleId,
|
|
3755
|
+
tabIndex: -1,
|
|
3576
3756
|
style: {
|
|
3577
3757
|
...styles13.container,
|
|
3578
3758
|
left: position.x,
|
|
@@ -3584,7 +3764,7 @@ function CollabPopup({
|
|
|
3584
3764
|
onMouseDown: handleMouseDown,
|
|
3585
3765
|
children: [
|
|
3586
3766
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-drag-handle": true, style: styles13.titleBar, children: [
|
|
3587
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles13.titleText, children: buildChannelName(patientData) }),
|
|
3767
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { id: titleId, style: styles13.titleText, children: buildChannelName(patientData) }),
|
|
3588
3768
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles13.titleActions, children: [
|
|
3589
3769
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3590
3770
|
"button",
|