@natoe/colab 0.1.16 → 0.1.17
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 +36 -14
- package/dist/index.d.ts +36 -14
- package/dist/index.js +241 -171
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +241 -171
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -519,8 +519,6 @@ var SHADOW = {
|
|
|
519
519
|
toast: "0 4px 12px rgba(0, 0, 0, 0.18)"
|
|
520
520
|
};
|
|
521
521
|
var Z_INDEX = {
|
|
522
|
-
/** Sticky day divider — above bubbles, below interactive popovers. */
|
|
523
|
-
sticky: 1,
|
|
524
522
|
/** Toasts inside a panel. */
|
|
525
523
|
toast: 20,
|
|
526
524
|
/** Floating CollabPopup dialog. */
|
|
@@ -1452,6 +1450,31 @@ function DicomIcon({ size = 18, color = "currentColor" }) {
|
|
|
1452
1450
|
}
|
|
1453
1451
|
);
|
|
1454
1452
|
}
|
|
1453
|
+
function OpenCaseIcon({
|
|
1454
|
+
size = 18,
|
|
1455
|
+
color = "currentColor"
|
|
1456
|
+
}) {
|
|
1457
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1458
|
+
"svg",
|
|
1459
|
+
{
|
|
1460
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1461
|
+
width: size,
|
|
1462
|
+
height: size,
|
|
1463
|
+
viewBox: "0 0 24 24",
|
|
1464
|
+
fill: "none",
|
|
1465
|
+
stroke: color,
|
|
1466
|
+
strokeWidth: "2",
|
|
1467
|
+
strokeLinecap: "round",
|
|
1468
|
+
strokeLinejoin: "round",
|
|
1469
|
+
"aria-hidden": "true",
|
|
1470
|
+
children: [
|
|
1471
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 4h6v6" }),
|
|
1472
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 4L11 13" }),
|
|
1473
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5" })
|
|
1474
|
+
]
|
|
1475
|
+
}
|
|
1476
|
+
);
|
|
1477
|
+
}
|
|
1455
1478
|
function PeopleIcon({ size = 18, color = "currentColor" }) {
|
|
1456
1479
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1457
1480
|
"svg",
|
|
@@ -1489,15 +1512,19 @@ function BackIcon({ size = 22, color = "currentColor" }) {
|
|
|
1489
1512
|
}
|
|
1490
1513
|
);
|
|
1491
1514
|
}
|
|
1515
|
+
function stripOrderIdSuffix(name) {
|
|
1516
|
+
return name.replace(/\s*-\s*\d{1,6}\s*$/, "").trim();
|
|
1517
|
+
}
|
|
1492
1518
|
function resolveDisplayName(patientData, displayName) {
|
|
1493
1519
|
const localComplete = !!patientData.labName && !!patientData.displayOrderId;
|
|
1494
|
-
|
|
1495
|
-
return
|
|
1520
|
+
const raw = localComplete ? buildChannelName(patientData) : cleanChannelName(displayName) || buildChannelName(patientData);
|
|
1521
|
+
return stripOrderIdSuffix(raw);
|
|
1496
1522
|
}
|
|
1497
1523
|
function PatientHeader({
|
|
1498
1524
|
patientData,
|
|
1499
1525
|
participants,
|
|
1500
1526
|
onOpenDicom,
|
|
1527
|
+
onOpenCase,
|
|
1501
1528
|
onOpenSettings,
|
|
1502
1529
|
onBack,
|
|
1503
1530
|
hideName = false,
|
|
@@ -1505,29 +1532,58 @@ function PatientHeader({
|
|
|
1505
1532
|
className
|
|
1506
1533
|
}) {
|
|
1507
1534
|
const hasDicom = !!(patientData.studyId && patientData.storageId);
|
|
1508
|
-
const
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
value: `${patientData.patientAge} \xB7 ${patientData.patientSex}`
|
|
1514
|
-
});
|
|
1515
|
-
} else if (patientData.patientAge) {
|
|
1516
|
-
meta.push({ key: "age", label: "Age", value: String(patientData.patientAge) });
|
|
1517
|
-
} else if (patientData.patientSex) {
|
|
1518
|
-
meta.push({ key: "sex", label: "Sex", value: String(patientData.patientSex) });
|
|
1519
|
-
}
|
|
1520
|
-
if (patientData.studyType) {
|
|
1521
|
-
meta.push({ key: "modality", label: "Modality", value: patientData.studyType });
|
|
1522
|
-
}
|
|
1535
|
+
const resolvedName = resolveDisplayName(patientData, displayName);
|
|
1536
|
+
const metaParts = [];
|
|
1537
|
+
if (patientData.patientAge) metaParts.push(String(patientData.patientAge));
|
|
1538
|
+
if (patientData.patientSex) metaParts.push(String(patientData.patientSex));
|
|
1539
|
+
if (patientData.studyType) metaParts.push(patientData.studyType);
|
|
1523
1540
|
if (patientData.bodyParts && patientData.bodyParts.length > 0) {
|
|
1524
|
-
|
|
1525
|
-
key: "body",
|
|
1526
|
-
label: "Body part",
|
|
1527
|
-
value: patientData.bodyParts.join(", ")
|
|
1528
|
-
});
|
|
1541
|
+
metaParts.push(patientData.bodyParts.join(", "));
|
|
1529
1542
|
}
|
|
1530
|
-
const hasActions = hasDicom && onOpenDicom || onOpenSettings;
|
|
1543
|
+
const hasActions = hasDicom && onOpenDicom || onOpenCase || onOpenSettings;
|
|
1544
|
+
const actions = hasActions ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.actions, children: [
|
|
1545
|
+
hasDicom && onOpenDicom && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1546
|
+
"button",
|
|
1547
|
+
{
|
|
1548
|
+
onClick: onOpenDicom,
|
|
1549
|
+
style: styles.dicomButton,
|
|
1550
|
+
type: "button",
|
|
1551
|
+
"aria-label": "View DICOM study",
|
|
1552
|
+
children: [
|
|
1553
|
+
/* @__PURE__ */ jsxRuntime.jsx(DicomIcon, { size: 18, color: COLOR.primary }),
|
|
1554
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "View DICOM" })
|
|
1555
|
+
]
|
|
1556
|
+
}
|
|
1557
|
+
),
|
|
1558
|
+
onOpenCase && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1559
|
+
"button",
|
|
1560
|
+
{
|
|
1561
|
+
onClick: onOpenCase,
|
|
1562
|
+
style: styles.openCaseButton,
|
|
1563
|
+
type: "button",
|
|
1564
|
+
"aria-label": "Open case",
|
|
1565
|
+
title: "Open case",
|
|
1566
|
+
children: [
|
|
1567
|
+
/* @__PURE__ */ jsxRuntime.jsx(OpenCaseIcon, { size: 18, color: COLOR.primary }),
|
|
1568
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Open" })
|
|
1569
|
+
]
|
|
1570
|
+
}
|
|
1571
|
+
),
|
|
1572
|
+
onOpenSettings && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1573
|
+
"button",
|
|
1574
|
+
{
|
|
1575
|
+
onClick: onOpenSettings,
|
|
1576
|
+
style: styles.settingsIconButton,
|
|
1577
|
+
type: "button",
|
|
1578
|
+
"aria-label": `Open channel settings (${participants.length} participants)`,
|
|
1579
|
+
title: "Channel participants",
|
|
1580
|
+
children: [
|
|
1581
|
+
/* @__PURE__ */ jsxRuntime.jsx(PeopleIcon, { size: 18, color: COLOR.neutral600 }),
|
|
1582
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.participantCount, children: participants.length })
|
|
1583
|
+
]
|
|
1584
|
+
}
|
|
1585
|
+
)
|
|
1586
|
+
] }) : null;
|
|
1531
1587
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: styles.container, children: [
|
|
1532
1588
|
!hideName && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.nameRow, children: [
|
|
1533
1589
|
onBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1538,46 +1594,14 @@ function PatientHeader({
|
|
|
1538
1594
|
style: styles.backButton,
|
|
1539
1595
|
"aria-label": "Back to conversations",
|
|
1540
1596
|
title: "Back to conversations",
|
|
1541
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(BackIcon, { size:
|
|
1597
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(BackIcon, { size: 20, color: COLOR.neutral800 })
|
|
1542
1598
|
}
|
|
1543
1599
|
),
|
|
1544
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.nameText, children:
|
|
1600
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.nameText, children: resolvedName }),
|
|
1601
|
+
actions
|
|
1545
1602
|
] }),
|
|
1546
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1547
|
-
|
|
1548
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.metaLabel, children: item.label }),
|
|
1549
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.metaValue, children: item.value })
|
|
1550
|
-
] }, item.key)) }),
|
|
1551
|
-
hasActions && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.actions, children: [
|
|
1552
|
-
hasDicom && onOpenDicom && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1553
|
-
"button",
|
|
1554
|
-
{
|
|
1555
|
-
onClick: onOpenDicom,
|
|
1556
|
-
style: styles.dicomButton,
|
|
1557
|
-
type: "button",
|
|
1558
|
-
"aria-label": "View DICOM study",
|
|
1559
|
-
children: [
|
|
1560
|
-
/* @__PURE__ */ jsxRuntime.jsx(DicomIcon, { size: 18, color: COLOR.primary }),
|
|
1561
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "View DICOM" })
|
|
1562
|
-
]
|
|
1563
|
-
}
|
|
1564
|
-
),
|
|
1565
|
-
onOpenSettings && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1566
|
-
"button",
|
|
1567
|
-
{
|
|
1568
|
-
onClick: onOpenSettings,
|
|
1569
|
-
style: styles.settingsIconButton,
|
|
1570
|
-
type: "button",
|
|
1571
|
-
"aria-label": `Open channel settings (${participants.length} participants)`,
|
|
1572
|
-
title: "Channel participants",
|
|
1573
|
-
children: [
|
|
1574
|
-
/* @__PURE__ */ jsxRuntime.jsx(PeopleIcon, { size: 18, color: COLOR.neutral600 }),
|
|
1575
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.participantCount, children: participants.length })
|
|
1576
|
-
]
|
|
1577
|
-
}
|
|
1578
|
-
)
|
|
1579
|
-
] })
|
|
1580
|
-
] })
|
|
1603
|
+
!hideName && metaParts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.metaRow, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.metaText, children: metaParts.join(" \xB7 ") }) }),
|
|
1604
|
+
hideName && actions && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.actionsOnlyRow, children: actions })
|
|
1581
1605
|
] });
|
|
1582
1606
|
}
|
|
1583
1607
|
var styles = {
|
|
@@ -1585,16 +1609,16 @@ var styles = {
|
|
|
1585
1609
|
display: "flex",
|
|
1586
1610
|
flexDirection: "column",
|
|
1587
1611
|
backgroundColor: COLOR.primaryBg,
|
|
1588
|
-
borderBottom: `1px solid ${COLOR.neutral200}
|
|
1612
|
+
borderBottom: `1px solid ${COLOR.neutral200}`,
|
|
1613
|
+
padding: `${SPACE.S2} ${SPACE.S4}`,
|
|
1614
|
+
gap: "2px"
|
|
1589
1615
|
},
|
|
1590
|
-
//
|
|
1616
|
+
// Title row — back · name · actions in one horizontal line.
|
|
1591
1617
|
nameRow: {
|
|
1592
1618
|
display: "flex",
|
|
1593
1619
|
alignItems: "center",
|
|
1594
1620
|
gap: SPACE.S2,
|
|
1595
|
-
|
|
1596
|
-
borderBottom: `1px solid ${COLOR.neutral200}`,
|
|
1597
|
-
backgroundColor: COLOR.white
|
|
1621
|
+
minWidth: 0
|
|
1598
1622
|
},
|
|
1599
1623
|
backButton: {
|
|
1600
1624
|
width: SIZE.controlIcon,
|
|
@@ -1610,57 +1634,45 @@ var styles = {
|
|
|
1610
1634
|
flexShrink: 0
|
|
1611
1635
|
},
|
|
1612
1636
|
nameText: {
|
|
1637
|
+
flex: 1,
|
|
1638
|
+
minWidth: 0,
|
|
1613
1639
|
fontSize: FONT_SIZE.lg,
|
|
1614
1640
|
fontWeight: FONT_WEIGHT.bold,
|
|
1615
1641
|
color: COLOR.neutral900,
|
|
1616
1642
|
lineHeight: LINE_HEIGHT.tight,
|
|
1617
1643
|
letterSpacing: "-0.01em",
|
|
1618
|
-
minWidth: 0,
|
|
1619
1644
|
overflow: "hidden",
|
|
1620
1645
|
textOverflow: "ellipsis",
|
|
1621
1646
|
whiteSpace: "nowrap"
|
|
1622
1647
|
},
|
|
1623
|
-
//
|
|
1624
|
-
//
|
|
1625
|
-
//
|
|
1626
|
-
caseCard: {
|
|
1627
|
-
display: "flex",
|
|
1628
|
-
flexDirection: "column",
|
|
1629
|
-
gap: SPACE.S3,
|
|
1630
|
-
padding: `${SPACE.S3} ${SPACE.S5}`
|
|
1631
|
-
},
|
|
1632
|
-
// Wrap-row of stacked label/value columns. Compact column gap keeps
|
|
1633
|
-
// the row dense without crowding; row gap kicks in when columns
|
|
1634
|
-
// wrap to a second line on narrow popups.
|
|
1648
|
+
// Sub-row beneath the title — small muted meta. Aligned under the
|
|
1649
|
+
// name (past the back button) so it visually anchors to the title
|
|
1650
|
+
// rather than the panel edge.
|
|
1635
1651
|
metaRow: {
|
|
1636
1652
|
display: "flex",
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
rowGap: SPACE.S2,
|
|
1653
|
+
alignItems: "center",
|
|
1654
|
+
paddingLeft: `calc(${SIZE.controlIcon} + ${SPACE.S2} - ${SPACE.S2})`,
|
|
1640
1655
|
minWidth: 0
|
|
1641
1656
|
},
|
|
1642
|
-
|
|
1657
|
+
// When hideName=true (popup mode), only the actions render. The
|
|
1658
|
+
// popup's own title bar carries the name + meta above this row, so
|
|
1659
|
+
// the actions land flush-left here — pinning them to the right
|
|
1660
|
+
// edge would leave the whole left half of the strip awkwardly
|
|
1661
|
+
// empty (the meta that used to fill it now lives in the title bar).
|
|
1662
|
+
actionsOnlyRow: {
|
|
1643
1663
|
display: "flex",
|
|
1644
|
-
|
|
1645
|
-
gap: "2px",
|
|
1664
|
+
justifyContent: "flex-start",
|
|
1646
1665
|
minWidth: 0
|
|
1647
1666
|
},
|
|
1648
|
-
|
|
1649
|
-
fontSize: "11px",
|
|
1650
|
-
fontWeight: FONT_WEIGHT.bold,
|
|
1651
|
-
letterSpacing: "0.06em",
|
|
1652
|
-
textTransform: "uppercase",
|
|
1653
|
-
color: COLOR.neutral500,
|
|
1654
|
-
whiteSpace: "nowrap"
|
|
1655
|
-
},
|
|
1656
|
-
metaValue: {
|
|
1667
|
+
metaText: {
|
|
1657
1668
|
fontSize: FONT_SIZE.sm,
|
|
1658
|
-
fontWeight: FONT_WEIGHT.
|
|
1659
|
-
color: COLOR.
|
|
1660
|
-
|
|
1669
|
+
fontWeight: FONT_WEIGHT.medium,
|
|
1670
|
+
color: COLOR.neutral600,
|
|
1671
|
+
lineHeight: LINE_HEIGHT.tight,
|
|
1661
1672
|
overflow: "hidden",
|
|
1662
1673
|
textOverflow: "ellipsis",
|
|
1663
|
-
|
|
1674
|
+
whiteSpace: "nowrap",
|
|
1675
|
+
minWidth: 0
|
|
1664
1676
|
},
|
|
1665
1677
|
actions: {
|
|
1666
1678
|
display: "flex",
|
|
@@ -1672,7 +1684,24 @@ var styles = {
|
|
|
1672
1684
|
alignItems: "center",
|
|
1673
1685
|
gap: SPACE.S2,
|
|
1674
1686
|
minHeight: SIZE.control,
|
|
1675
|
-
padding: `${SPACE.
|
|
1687
|
+
padding: `${SPACE.S1} ${SPACE.S3}`,
|
|
1688
|
+
fontSize: FONT_SIZE.sm,
|
|
1689
|
+
fontWeight: FONT_WEIGHT.semibold,
|
|
1690
|
+
color: COLOR.primary,
|
|
1691
|
+
backgroundColor: COLOR.white,
|
|
1692
|
+
border: `1.5px solid ${COLOR.primary}`,
|
|
1693
|
+
borderRadius: RADIUS.lg,
|
|
1694
|
+
cursor: "pointer"
|
|
1695
|
+
},
|
|
1696
|
+
// Sibling of the DICOM button — same shape so the two read as a pair.
|
|
1697
|
+
// Click hands off to the host's `onOpenCase` callback (role-aware
|
|
1698
|
+
// routing lives on the host side).
|
|
1699
|
+
openCaseButton: {
|
|
1700
|
+
display: "inline-flex",
|
|
1701
|
+
alignItems: "center",
|
|
1702
|
+
gap: SPACE.S2,
|
|
1703
|
+
minHeight: SIZE.control,
|
|
1704
|
+
padding: `${SPACE.S1} ${SPACE.S3}`,
|
|
1676
1705
|
fontSize: FONT_SIZE.sm,
|
|
1677
1706
|
fontWeight: FONT_WEIGHT.semibold,
|
|
1678
1707
|
color: COLOR.primary,
|
|
@@ -1681,10 +1710,8 @@ var styles = {
|
|
|
1681
1710
|
borderRadius: RADIUS.lg,
|
|
1682
1711
|
cursor: "pointer"
|
|
1683
1712
|
},
|
|
1684
|
-
// Channel-info button: people icon + participant count.
|
|
1685
|
-
// channel settings overlay
|
|
1686
|
-
// don't have to re-wire — the affordance just looks like a "members"
|
|
1687
|
-
// pill now instead of a gear).
|
|
1713
|
+
// Channel-info button: people icon + participant count. Opens the
|
|
1714
|
+
// channel settings overlay.
|
|
1688
1715
|
settingsIconButton: {
|
|
1689
1716
|
minHeight: SIZE.control,
|
|
1690
1717
|
display: "inline-flex",
|
|
@@ -2164,6 +2191,62 @@ function AlertIcon({ size = 14, color = "currentColor" }) {
|
|
|
2164
2191
|
}
|
|
2165
2192
|
);
|
|
2166
2193
|
}
|
|
2194
|
+
function RoleAvatarIcon({
|
|
2195
|
+
role,
|
|
2196
|
+
size = 18,
|
|
2197
|
+
color = "currentColor",
|
|
2198
|
+
className
|
|
2199
|
+
}) {
|
|
2200
|
+
const common = {
|
|
2201
|
+
width: size,
|
|
2202
|
+
height: size,
|
|
2203
|
+
viewBox: "0 0 24 24",
|
|
2204
|
+
fill: "none",
|
|
2205
|
+
stroke: color,
|
|
2206
|
+
strokeWidth: 1.9,
|
|
2207
|
+
strokeLinecap: "round",
|
|
2208
|
+
strokeLinejoin: "round",
|
|
2209
|
+
"aria-hidden": true,
|
|
2210
|
+
className
|
|
2211
|
+
};
|
|
2212
|
+
switch (role) {
|
|
2213
|
+
case "radiologist":
|
|
2214
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...common, children: [
|
|
2215
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7.5 8.5h9" }),
|
|
2216
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "9.5", r: "4" }),
|
|
2217
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "7.5", r: "1", fill: color, stroke: "none" }),
|
|
2218
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 21v-1.5a5 5 0 0 1 5-5h6a5 5 0 0 1 5 5V21" })
|
|
2219
|
+
] });
|
|
2220
|
+
case "lab":
|
|
2221
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...common, children: [
|
|
2222
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 21V9l9-6 9 6v12" }),
|
|
2223
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 11v6" }),
|
|
2224
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 14h6" }),
|
|
2225
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M11 21v-3h2v3" }),
|
|
2226
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 21h18" })
|
|
2227
|
+
] });
|
|
2228
|
+
case "physician":
|
|
2229
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...common, children: [
|
|
2230
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 3v5a4 4 0 0 0 8 0V3" }),
|
|
2231
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 3h2" }),
|
|
2232
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 3h2" }),
|
|
2233
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M11 12v3a5 5 0 0 0 5 5h0a5 5 0 0 0 5-5v-2" }),
|
|
2234
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "21", cy: "11", r: "2" })
|
|
2235
|
+
] });
|
|
2236
|
+
case "admin":
|
|
2237
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...common, children: [
|
|
2238
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "3" }),
|
|
2239
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2v3" }),
|
|
2240
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 19v3" }),
|
|
2241
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 12H2" }),
|
|
2242
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M22 12h-3" }),
|
|
2243
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5.6 5.6l2 2" }),
|
|
2244
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16.4 16.4l2 2" }),
|
|
2245
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5.6 18.4l2-2" }),
|
|
2246
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16.4 7.6l2-2" })
|
|
2247
|
+
] });
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2167
2250
|
function Spinner({ size = 16, color = COLOR.neutral500, thickness = 2 }) {
|
|
2168
2251
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2169
2252
|
"span",
|
|
@@ -2252,12 +2335,11 @@ function MessageBubble({
|
|
|
2252
2335
|
...styles5.authorAvatar,
|
|
2253
2336
|
backgroundColor: roleColor(message.senderRole)
|
|
2254
2337
|
},
|
|
2255
|
-
"aria-
|
|
2256
|
-
children:
|
|
2338
|
+
"aria-label": ROLE_LABELS[message.senderRole] ?? message.senderRole,
|
|
2339
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RoleAvatarIcon, { role: message.senderRole, size: 20, color: COLOR.white })
|
|
2257
2340
|
}
|
|
2258
2341
|
),
|
|
2259
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.authorName, children: message.senderName })
|
|
2260
|
-
/* @__PURE__ */ jsxRuntime.jsx(RoleBadge, { role: message.senderRole })
|
|
2342
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.authorName, children: message.senderName })
|
|
2261
2343
|
] }),
|
|
2262
2344
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2263
2345
|
"div",
|
|
@@ -2332,9 +2414,6 @@ function MessageBubble({
|
|
|
2332
2414
|
}
|
|
2333
2415
|
);
|
|
2334
2416
|
}
|
|
2335
|
-
function computeInitials(name) {
|
|
2336
|
-
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((p) => p[0]?.toUpperCase() ?? "").join("") || "?";
|
|
2337
|
-
}
|
|
2338
2417
|
function roleColor(role) {
|
|
2339
2418
|
switch (role) {
|
|
2340
2419
|
case "radiologist":
|
|
@@ -2419,9 +2498,6 @@ function SystemBubble({ message }) {
|
|
|
2419
2498
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.systemTime, children: formatTime(message.insertedAt) })
|
|
2420
2499
|
] }) });
|
|
2421
2500
|
}
|
|
2422
|
-
function RoleBadge({ role }) {
|
|
2423
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles5.roleBadge, backgroundColor: roleColor(role) }, children: ROLE_LABELS[role] ?? role });
|
|
2424
|
-
}
|
|
2425
2501
|
function formatTime(iso) {
|
|
2426
2502
|
try {
|
|
2427
2503
|
return new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
@@ -2523,16 +2599,6 @@ var styles5 = {
|
|
|
2523
2599
|
color: "#fff4d6",
|
|
2524
2600
|
backgroundColor: "rgba(255, 255, 255, 0.2)"
|
|
2525
2601
|
},
|
|
2526
|
-
roleBadge: {
|
|
2527
|
-
fontSize: "10px",
|
|
2528
|
-
fontWeight: FONT_WEIGHT.bold,
|
|
2529
|
-
padding: "2px 7px",
|
|
2530
|
-
borderRadius: RADIUS.sm,
|
|
2531
|
-
textTransform: "uppercase",
|
|
2532
|
-
letterSpacing: "0.06em",
|
|
2533
|
-
color: COLOR.white,
|
|
2534
|
-
flexShrink: 0
|
|
2535
|
-
},
|
|
2536
2602
|
textBody: {
|
|
2537
2603
|
margin: 0,
|
|
2538
2604
|
fontSize: FONT_SIZE.md,
|
|
@@ -2996,9 +3062,6 @@ var styles6 = {
|
|
|
2996
3062
|
alignItems: "center",
|
|
2997
3063
|
gap: SPACE.S3,
|
|
2998
3064
|
margin: `${SPACE.S4} 0 ${SPACE.S3}`,
|
|
2999
|
-
position: "sticky",
|
|
3000
|
-
top: SPACE.S1,
|
|
3001
|
-
zIndex: Z_INDEX.sticky,
|
|
3002
3065
|
pointerEvents: "none"
|
|
3003
3066
|
},
|
|
3004
3067
|
dayHr: {
|
|
@@ -3013,11 +3076,7 @@ var styles6 = {
|
|
|
3013
3076
|
color: COLOR.neutral500,
|
|
3014
3077
|
textTransform: "uppercase",
|
|
3015
3078
|
letterSpacing: "0.06em",
|
|
3016
|
-
// Subtle pill background so the label is readable when it overlays
|
|
3017
|
-
// bubbles passing under it during sticky scroll. Without this the
|
|
3018
|
-
// hairlines visually run through the text on tinted backgrounds.
|
|
3019
3079
|
padding: `2px ${SPACE.S2}`,
|
|
3020
|
-
backgroundColor: COLOR.white,
|
|
3021
3080
|
borderRadius: RADIUS.sm
|
|
3022
3081
|
},
|
|
3023
3082
|
bubbleSlot: {
|
|
@@ -3315,7 +3374,7 @@ function MessageInput({
|
|
|
3315
3374
|
style: styles8.textarea
|
|
3316
3375
|
}
|
|
3317
3376
|
),
|
|
3318
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3377
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3319
3378
|
"button",
|
|
3320
3379
|
{
|
|
3321
3380
|
onClick: handleSendText,
|
|
@@ -3327,10 +3386,7 @@ function MessageInput({
|
|
|
3327
3386
|
opacity: text.trim() ? 1 : 0.5
|
|
3328
3387
|
},
|
|
3329
3388
|
type: "button",
|
|
3330
|
-
children:
|
|
3331
|
-
/* @__PURE__ */ jsxRuntime.jsx(SendIcon, { size: 20, color: COLOR.white }),
|
|
3332
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.sendLabel, children: "Send" })
|
|
3333
|
-
]
|
|
3389
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SendIcon, { size: 20, color: COLOR.white })
|
|
3334
3390
|
}
|
|
3335
3391
|
)
|
|
3336
3392
|
] })
|
|
@@ -3428,29 +3484,33 @@ var styles8 = {
|
|
|
3428
3484
|
fontFamily: "inherit",
|
|
3429
3485
|
transition: "background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease"
|
|
3430
3486
|
},
|
|
3431
|
-
//
|
|
3432
|
-
//
|
|
3487
|
+
// Square icon-only send button. The arrow inside an obvious input
|
|
3488
|
+
// context is affordance enough; the word "Send" used to sit next to
|
|
3489
|
+
// it but added clutter without disambiguating anything.
|
|
3433
3490
|
sendButton: {
|
|
3434
3491
|
display: "inline-flex",
|
|
3435
3492
|
alignItems: "center",
|
|
3436
|
-
|
|
3437
|
-
|
|
3493
|
+
justifyContent: "center",
|
|
3494
|
+
width: "48px",
|
|
3438
3495
|
height: "48px",
|
|
3439
|
-
padding: `0 ${SPACE.S4}`,
|
|
3440
3496
|
backgroundColor: COLOR.primary,
|
|
3441
3497
|
color: COLOR.white,
|
|
3442
3498
|
border: "none",
|
|
3443
3499
|
borderRadius: "14px",
|
|
3444
3500
|
cursor: "pointer",
|
|
3445
3501
|
flexShrink: 0,
|
|
3446
|
-
fontFamily: "inherit",
|
|
3447
|
-
fontSize: "15px",
|
|
3448
|
-
fontWeight: FONT_WEIGHT.semibold,
|
|
3449
3502
|
transition: "opacity 120ms ease, background-color 120ms ease"
|
|
3450
|
-
},
|
|
3451
|
-
sendLabel: {
|
|
3452
|
-
lineHeight: 1
|
|
3453
3503
|
}};
|
|
3504
|
+
var ROLE_AVATAR_BG = {
|
|
3505
|
+
radiologist: "#4f46e5",
|
|
3506
|
+
// indigo
|
|
3507
|
+
lab: "#2563eb",
|
|
3508
|
+
// brand blue
|
|
3509
|
+
physician: "#0284c7",
|
|
3510
|
+
// sky
|
|
3511
|
+
admin: "#64748b"
|
|
3512
|
+
// slate
|
|
3513
|
+
};
|
|
3454
3514
|
function ParticipantsList({
|
|
3455
3515
|
participants,
|
|
3456
3516
|
currentUserId,
|
|
@@ -3460,7 +3520,17 @@ function ParticipantsList({
|
|
|
3460
3520
|
}) {
|
|
3461
3521
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: styles9.list, children: participants.map((participant) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.item, children: [
|
|
3462
3522
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.avatar, children: [
|
|
3463
|
-
participant.avatar ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: participant.avatar, alt: "", style: styles9.avatarImg }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3523
|
+
participant.avatar ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: participant.avatar, alt: "", style: styles9.avatarImg }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3524
|
+
"span",
|
|
3525
|
+
{
|
|
3526
|
+
style: {
|
|
3527
|
+
...styles9.avatarFallback,
|
|
3528
|
+
backgroundColor: ROLE_AVATAR_BG[participant.userRole]
|
|
3529
|
+
},
|
|
3530
|
+
"aria-hidden": "true",
|
|
3531
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RoleAvatarIcon, { role: participant.userRole, size: 18, color: COLOR.white })
|
|
3532
|
+
}
|
|
3533
|
+
),
|
|
3464
3534
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3465
3535
|
"span",
|
|
3466
3536
|
{
|
|
@@ -3476,7 +3546,7 @@ function ParticipantsList({
|
|
|
3476
3546
|
participant.userName ?? fallbackName(participant.userRole),
|
|
3477
3547
|
participant.userId === currentUserId && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.youBadge, children: " (you)" })
|
|
3478
3548
|
] }),
|
|
3479
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3549
|
+
/* @__PURE__ */ jsxRuntime.jsx(RoleBadge, { role: participant.userRole })
|
|
3480
3550
|
] }),
|
|
3481
3551
|
isAdmin && participant.userId !== currentUserId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3482
3552
|
"button",
|
|
@@ -3504,7 +3574,7 @@ function fallbackName(role) {
|
|
|
3504
3574
|
return "User";
|
|
3505
3575
|
}
|
|
3506
3576
|
}
|
|
3507
|
-
function
|
|
3577
|
+
function RoleBadge({ role }) {
|
|
3508
3578
|
const colors = {
|
|
3509
3579
|
radiologist: { bg: "#eef2ff", text: "#4f46e5" },
|
|
3510
3580
|
// indigo
|
|
@@ -3546,13 +3616,10 @@ var styles9 = {
|
|
|
3546
3616
|
width: "32px",
|
|
3547
3617
|
height: "32px",
|
|
3548
3618
|
borderRadius: RADIUS.full,
|
|
3549
|
-
backgroundColor: COLOR.neutral200,
|
|
3550
3619
|
display: "flex",
|
|
3551
3620
|
alignItems: "center",
|
|
3552
3621
|
justifyContent: "center",
|
|
3553
|
-
|
|
3554
|
-
fontWeight: FONT_WEIGHT.semibold,
|
|
3555
|
-
color: COLOR.neutral500
|
|
3622
|
+
color: COLOR.white
|
|
3556
3623
|
},
|
|
3557
3624
|
statusDot: {
|
|
3558
3625
|
position: "absolute",
|
|
@@ -4144,6 +4211,7 @@ function CollabPanel({
|
|
|
4144
4211
|
showSeenBy = true,
|
|
4145
4212
|
onBack,
|
|
4146
4213
|
hidePatientName = false,
|
|
4214
|
+
hideOpenCase = false,
|
|
4147
4215
|
onConversationChange,
|
|
4148
4216
|
themeMode = "light",
|
|
4149
4217
|
className,
|
|
@@ -4186,6 +4254,7 @@ function CollabPanel({
|
|
|
4186
4254
|
config.onOpenDicom(patientData.studyId, patientData.storageId);
|
|
4187
4255
|
}
|
|
4188
4256
|
};
|
|
4257
|
+
const handleOpenCase = !hideOpenCase && config.onOpenCase ? () => config.onOpenCase?.(patientData.orderId, patientData.displayOrderId) : void 0;
|
|
4189
4258
|
const handleJumpToMessage = (messageId) => {
|
|
4190
4259
|
messageListRef.current?.scrollToMessage(messageId);
|
|
4191
4260
|
};
|
|
@@ -4261,6 +4330,7 @@ function CollabPanel({
|
|
|
4261
4330
|
patientData,
|
|
4262
4331
|
participants,
|
|
4263
4332
|
onOpenDicom: handleOpenDicom,
|
|
4333
|
+
onOpenCase: handleOpenCase,
|
|
4264
4334
|
onOpenSettings: () => setShowSettings(true),
|
|
4265
4335
|
onBack,
|
|
4266
4336
|
hideName: hidePatientName,
|
|
@@ -4515,14 +4585,16 @@ function CollabPopup({
|
|
|
4515
4585
|
),
|
|
4516
4586
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles13.titleCenter, children: [
|
|
4517
4587
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { id: titleId, style: styles13.patientName, children: patientData.patientName || titleText }),
|
|
4518
|
-
(
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
patientData.
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4588
|
+
(() => {
|
|
4589
|
+
const parts = [];
|
|
4590
|
+
if (patientData.patientAge) parts.push(String(patientData.patientAge));
|
|
4591
|
+
if (patientData.patientSex) parts.push(String(patientData.patientSex));
|
|
4592
|
+
if (patientData.studyType) parts.push(patientData.studyType);
|
|
4593
|
+
if (patientData.bodyParts && patientData.bodyParts.length > 0) {
|
|
4594
|
+
parts.push(patientData.bodyParts.join(", "));
|
|
4595
|
+
}
|
|
4596
|
+
return parts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles13.subRow, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles13.metaText, children: parts.join(" \xB7 ") }) }) : null;
|
|
4597
|
+
})()
|
|
4526
4598
|
] }),
|
|
4527
4599
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles13.titleActions, children: [
|
|
4528
4600
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4611,19 +4683,17 @@ var styles13 = {
|
|
|
4611
4683
|
subRow: {
|
|
4612
4684
|
display: "flex",
|
|
4613
4685
|
alignItems: "center",
|
|
4614
|
-
gap: SPACE.S2,
|
|
4615
4686
|
fontSize: FONT_SIZE.sm,
|
|
4616
4687
|
color: COLOR.neutral500,
|
|
4617
4688
|
overflow: "hidden",
|
|
4618
4689
|
textOverflow: "ellipsis",
|
|
4619
4690
|
whiteSpace: "nowrap"
|
|
4620
4691
|
},
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
fontVariantNumeric: "tabular-nums"
|
|
4692
|
+
metaText: {
|
|
4693
|
+
overflow: "hidden",
|
|
4694
|
+
textOverflow: "ellipsis",
|
|
4695
|
+
whiteSpace: "nowrap",
|
|
4696
|
+
minWidth: 0
|
|
4627
4697
|
},
|
|
4628
4698
|
titleActions: {
|
|
4629
4699
|
display: "flex",
|
|
@@ -5436,7 +5506,7 @@ function ConversationListItem({
|
|
|
5436
5506
|
const studyType = item.patientSnapshot?.studyType;
|
|
5437
5507
|
const patientId = item.patientSnapshot?.patientId;
|
|
5438
5508
|
const showStudyRow = !!(studyType || patientId);
|
|
5439
|
-
const initials =
|
|
5509
|
+
const initials = computeInitials(item.patientSnapshot?.patientName || displayName);
|
|
5440
5510
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5441
5511
|
"button",
|
|
5442
5512
|
{
|
|
@@ -5531,7 +5601,7 @@ function previewText(message) {
|
|
|
5531
5601
|
}
|
|
5532
5602
|
}
|
|
5533
5603
|
}
|
|
5534
|
-
function
|
|
5604
|
+
function computeInitials(name) {
|
|
5535
5605
|
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase() ?? "").join("") || "?";
|
|
5536
5606
|
}
|
|
5537
5607
|
var styles15 = {
|