@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.mjs
CHANGED
|
@@ -513,8 +513,6 @@ var SHADOW = {
|
|
|
513
513
|
toast: "0 4px 12px rgba(0, 0, 0, 0.18)"
|
|
514
514
|
};
|
|
515
515
|
var Z_INDEX = {
|
|
516
|
-
/** Sticky day divider — above bubbles, below interactive popovers. */
|
|
517
|
-
sticky: 1,
|
|
518
516
|
/** Toasts inside a panel. */
|
|
519
517
|
toast: 20,
|
|
520
518
|
/** Floating CollabPopup dialog. */
|
|
@@ -1446,6 +1444,31 @@ function DicomIcon({ size = 18, color = "currentColor" }) {
|
|
|
1446
1444
|
}
|
|
1447
1445
|
);
|
|
1448
1446
|
}
|
|
1447
|
+
function OpenCaseIcon({
|
|
1448
|
+
size = 18,
|
|
1449
|
+
color = "currentColor"
|
|
1450
|
+
}) {
|
|
1451
|
+
return /* @__PURE__ */ jsxs(
|
|
1452
|
+
"svg",
|
|
1453
|
+
{
|
|
1454
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1455
|
+
width: size,
|
|
1456
|
+
height: size,
|
|
1457
|
+
viewBox: "0 0 24 24",
|
|
1458
|
+
fill: "none",
|
|
1459
|
+
stroke: color,
|
|
1460
|
+
strokeWidth: "2",
|
|
1461
|
+
strokeLinecap: "round",
|
|
1462
|
+
strokeLinejoin: "round",
|
|
1463
|
+
"aria-hidden": "true",
|
|
1464
|
+
children: [
|
|
1465
|
+
/* @__PURE__ */ jsx("path", { d: "M14 4h6v6" }),
|
|
1466
|
+
/* @__PURE__ */ jsx("path", { d: "M20 4L11 13" }),
|
|
1467
|
+
/* @__PURE__ */ jsx("path", { d: "M20 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5" })
|
|
1468
|
+
]
|
|
1469
|
+
}
|
|
1470
|
+
);
|
|
1471
|
+
}
|
|
1449
1472
|
function PeopleIcon({ size = 18, color = "currentColor" }) {
|
|
1450
1473
|
return /* @__PURE__ */ jsxs(
|
|
1451
1474
|
"svg",
|
|
@@ -1483,15 +1506,19 @@ function BackIcon({ size = 22, color = "currentColor" }) {
|
|
|
1483
1506
|
}
|
|
1484
1507
|
);
|
|
1485
1508
|
}
|
|
1509
|
+
function stripOrderIdSuffix(name) {
|
|
1510
|
+
return name.replace(/\s*-\s*\d{1,6}\s*$/, "").trim();
|
|
1511
|
+
}
|
|
1486
1512
|
function resolveDisplayName(patientData, displayName) {
|
|
1487
1513
|
const localComplete = !!patientData.labName && !!patientData.displayOrderId;
|
|
1488
|
-
|
|
1489
|
-
return
|
|
1514
|
+
const raw = localComplete ? buildChannelName(patientData) : cleanChannelName(displayName) || buildChannelName(patientData);
|
|
1515
|
+
return stripOrderIdSuffix(raw);
|
|
1490
1516
|
}
|
|
1491
1517
|
function PatientHeader({
|
|
1492
1518
|
patientData,
|
|
1493
1519
|
participants,
|
|
1494
1520
|
onOpenDicom,
|
|
1521
|
+
onOpenCase,
|
|
1495
1522
|
onOpenSettings,
|
|
1496
1523
|
onBack,
|
|
1497
1524
|
hideName = false,
|
|
@@ -1499,29 +1526,58 @@ function PatientHeader({
|
|
|
1499
1526
|
className
|
|
1500
1527
|
}) {
|
|
1501
1528
|
const hasDicom = !!(patientData.studyId && patientData.storageId);
|
|
1502
|
-
const
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
value: `${patientData.patientAge} \xB7 ${patientData.patientSex}`
|
|
1508
|
-
});
|
|
1509
|
-
} else if (patientData.patientAge) {
|
|
1510
|
-
meta.push({ key: "age", label: "Age", value: String(patientData.patientAge) });
|
|
1511
|
-
} else if (patientData.patientSex) {
|
|
1512
|
-
meta.push({ key: "sex", label: "Sex", value: String(patientData.patientSex) });
|
|
1513
|
-
}
|
|
1514
|
-
if (patientData.studyType) {
|
|
1515
|
-
meta.push({ key: "modality", label: "Modality", value: patientData.studyType });
|
|
1516
|
-
}
|
|
1529
|
+
const resolvedName = resolveDisplayName(patientData, displayName);
|
|
1530
|
+
const metaParts = [];
|
|
1531
|
+
if (patientData.patientAge) metaParts.push(String(patientData.patientAge));
|
|
1532
|
+
if (patientData.patientSex) metaParts.push(String(patientData.patientSex));
|
|
1533
|
+
if (patientData.studyType) metaParts.push(patientData.studyType);
|
|
1517
1534
|
if (patientData.bodyParts && patientData.bodyParts.length > 0) {
|
|
1518
|
-
|
|
1519
|
-
key: "body",
|
|
1520
|
-
label: "Body part",
|
|
1521
|
-
value: patientData.bodyParts.join(", ")
|
|
1522
|
-
});
|
|
1535
|
+
metaParts.push(patientData.bodyParts.join(", "));
|
|
1523
1536
|
}
|
|
1524
|
-
const hasActions = hasDicom && onOpenDicom || onOpenSettings;
|
|
1537
|
+
const hasActions = hasDicom && onOpenDicom || onOpenCase || onOpenSettings;
|
|
1538
|
+
const actions = hasActions ? /* @__PURE__ */ jsxs("div", { style: styles.actions, children: [
|
|
1539
|
+
hasDicom && onOpenDicom && /* @__PURE__ */ jsxs(
|
|
1540
|
+
"button",
|
|
1541
|
+
{
|
|
1542
|
+
onClick: onOpenDicom,
|
|
1543
|
+
style: styles.dicomButton,
|
|
1544
|
+
type: "button",
|
|
1545
|
+
"aria-label": "View DICOM study",
|
|
1546
|
+
children: [
|
|
1547
|
+
/* @__PURE__ */ jsx(DicomIcon, { size: 18, color: COLOR.primary }),
|
|
1548
|
+
/* @__PURE__ */ jsx("span", { children: "View DICOM" })
|
|
1549
|
+
]
|
|
1550
|
+
}
|
|
1551
|
+
),
|
|
1552
|
+
onOpenCase && /* @__PURE__ */ jsxs(
|
|
1553
|
+
"button",
|
|
1554
|
+
{
|
|
1555
|
+
onClick: onOpenCase,
|
|
1556
|
+
style: styles.openCaseButton,
|
|
1557
|
+
type: "button",
|
|
1558
|
+
"aria-label": "Open case",
|
|
1559
|
+
title: "Open case",
|
|
1560
|
+
children: [
|
|
1561
|
+
/* @__PURE__ */ jsx(OpenCaseIcon, { size: 18, color: COLOR.primary }),
|
|
1562
|
+
/* @__PURE__ */ jsx("span", { children: "Open" })
|
|
1563
|
+
]
|
|
1564
|
+
}
|
|
1565
|
+
),
|
|
1566
|
+
onOpenSettings && /* @__PURE__ */ jsxs(
|
|
1567
|
+
"button",
|
|
1568
|
+
{
|
|
1569
|
+
onClick: onOpenSettings,
|
|
1570
|
+
style: styles.settingsIconButton,
|
|
1571
|
+
type: "button",
|
|
1572
|
+
"aria-label": `Open channel settings (${participants.length} participants)`,
|
|
1573
|
+
title: "Channel participants",
|
|
1574
|
+
children: [
|
|
1575
|
+
/* @__PURE__ */ jsx(PeopleIcon, { size: 18, color: COLOR.neutral600 }),
|
|
1576
|
+
/* @__PURE__ */ jsx("span", { style: styles.participantCount, children: participants.length })
|
|
1577
|
+
]
|
|
1578
|
+
}
|
|
1579
|
+
)
|
|
1580
|
+
] }) : null;
|
|
1525
1581
|
return /* @__PURE__ */ jsxs("div", { className, style: styles.container, children: [
|
|
1526
1582
|
!hideName && /* @__PURE__ */ jsxs("div", { style: styles.nameRow, children: [
|
|
1527
1583
|
onBack && /* @__PURE__ */ jsx(
|
|
@@ -1532,46 +1588,14 @@ function PatientHeader({
|
|
|
1532
1588
|
style: styles.backButton,
|
|
1533
1589
|
"aria-label": "Back to conversations",
|
|
1534
1590
|
title: "Back to conversations",
|
|
1535
|
-
children: /* @__PURE__ */ jsx(BackIcon, { size:
|
|
1591
|
+
children: /* @__PURE__ */ jsx(BackIcon, { size: 20, color: COLOR.neutral800 })
|
|
1536
1592
|
}
|
|
1537
1593
|
),
|
|
1538
|
-
/* @__PURE__ */ jsx("span", { style: styles.nameText, children:
|
|
1594
|
+
/* @__PURE__ */ jsx("span", { style: styles.nameText, children: resolvedName }),
|
|
1595
|
+
actions
|
|
1539
1596
|
] }),
|
|
1540
|
-
/* @__PURE__ */
|
|
1541
|
-
|
|
1542
|
-
/* @__PURE__ */ jsx("span", { style: styles.metaLabel, children: item.label }),
|
|
1543
|
-
/* @__PURE__ */ jsx("span", { style: styles.metaValue, children: item.value })
|
|
1544
|
-
] }, item.key)) }),
|
|
1545
|
-
hasActions && /* @__PURE__ */ jsxs("div", { style: styles.actions, children: [
|
|
1546
|
-
hasDicom && onOpenDicom && /* @__PURE__ */ jsxs(
|
|
1547
|
-
"button",
|
|
1548
|
-
{
|
|
1549
|
-
onClick: onOpenDicom,
|
|
1550
|
-
style: styles.dicomButton,
|
|
1551
|
-
type: "button",
|
|
1552
|
-
"aria-label": "View DICOM study",
|
|
1553
|
-
children: [
|
|
1554
|
-
/* @__PURE__ */ jsx(DicomIcon, { size: 18, color: COLOR.primary }),
|
|
1555
|
-
/* @__PURE__ */ jsx("span", { children: "View DICOM" })
|
|
1556
|
-
]
|
|
1557
|
-
}
|
|
1558
|
-
),
|
|
1559
|
-
onOpenSettings && /* @__PURE__ */ jsxs(
|
|
1560
|
-
"button",
|
|
1561
|
-
{
|
|
1562
|
-
onClick: onOpenSettings,
|
|
1563
|
-
style: styles.settingsIconButton,
|
|
1564
|
-
type: "button",
|
|
1565
|
-
"aria-label": `Open channel settings (${participants.length} participants)`,
|
|
1566
|
-
title: "Channel participants",
|
|
1567
|
-
children: [
|
|
1568
|
-
/* @__PURE__ */ jsx(PeopleIcon, { size: 18, color: COLOR.neutral600 }),
|
|
1569
|
-
/* @__PURE__ */ jsx("span", { style: styles.participantCount, children: participants.length })
|
|
1570
|
-
]
|
|
1571
|
-
}
|
|
1572
|
-
)
|
|
1573
|
-
] })
|
|
1574
|
-
] })
|
|
1597
|
+
!hideName && metaParts.length > 0 && /* @__PURE__ */ jsx("div", { style: styles.metaRow, children: /* @__PURE__ */ jsx("span", { style: styles.metaText, children: metaParts.join(" \xB7 ") }) }),
|
|
1598
|
+
hideName && actions && /* @__PURE__ */ jsx("div", { style: styles.actionsOnlyRow, children: actions })
|
|
1575
1599
|
] });
|
|
1576
1600
|
}
|
|
1577
1601
|
var styles = {
|
|
@@ -1579,16 +1603,16 @@ var styles = {
|
|
|
1579
1603
|
display: "flex",
|
|
1580
1604
|
flexDirection: "column",
|
|
1581
1605
|
backgroundColor: COLOR.primaryBg,
|
|
1582
|
-
borderBottom: `1px solid ${COLOR.neutral200}
|
|
1606
|
+
borderBottom: `1px solid ${COLOR.neutral200}`,
|
|
1607
|
+
padding: `${SPACE.S2} ${SPACE.S4}`,
|
|
1608
|
+
gap: "2px"
|
|
1583
1609
|
},
|
|
1584
|
-
//
|
|
1610
|
+
// Title row — back · name · actions in one horizontal line.
|
|
1585
1611
|
nameRow: {
|
|
1586
1612
|
display: "flex",
|
|
1587
1613
|
alignItems: "center",
|
|
1588
1614
|
gap: SPACE.S2,
|
|
1589
|
-
|
|
1590
|
-
borderBottom: `1px solid ${COLOR.neutral200}`,
|
|
1591
|
-
backgroundColor: COLOR.white
|
|
1615
|
+
minWidth: 0
|
|
1592
1616
|
},
|
|
1593
1617
|
backButton: {
|
|
1594
1618
|
width: SIZE.controlIcon,
|
|
@@ -1604,57 +1628,45 @@ var styles = {
|
|
|
1604
1628
|
flexShrink: 0
|
|
1605
1629
|
},
|
|
1606
1630
|
nameText: {
|
|
1631
|
+
flex: 1,
|
|
1632
|
+
minWidth: 0,
|
|
1607
1633
|
fontSize: FONT_SIZE.lg,
|
|
1608
1634
|
fontWeight: FONT_WEIGHT.bold,
|
|
1609
1635
|
color: COLOR.neutral900,
|
|
1610
1636
|
lineHeight: LINE_HEIGHT.tight,
|
|
1611
1637
|
letterSpacing: "-0.01em",
|
|
1612
|
-
minWidth: 0,
|
|
1613
1638
|
overflow: "hidden",
|
|
1614
1639
|
textOverflow: "ellipsis",
|
|
1615
1640
|
whiteSpace: "nowrap"
|
|
1616
1641
|
},
|
|
1617
|
-
//
|
|
1618
|
-
//
|
|
1619
|
-
//
|
|
1620
|
-
caseCard: {
|
|
1621
|
-
display: "flex",
|
|
1622
|
-
flexDirection: "column",
|
|
1623
|
-
gap: SPACE.S3,
|
|
1624
|
-
padding: `${SPACE.S3} ${SPACE.S5}`
|
|
1625
|
-
},
|
|
1626
|
-
// Wrap-row of stacked label/value columns. Compact column gap keeps
|
|
1627
|
-
// the row dense without crowding; row gap kicks in when columns
|
|
1628
|
-
// wrap to a second line on narrow popups.
|
|
1642
|
+
// Sub-row beneath the title — small muted meta. Aligned under the
|
|
1643
|
+
// name (past the back button) so it visually anchors to the title
|
|
1644
|
+
// rather than the panel edge.
|
|
1629
1645
|
metaRow: {
|
|
1630
1646
|
display: "flex",
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
rowGap: SPACE.S2,
|
|
1647
|
+
alignItems: "center",
|
|
1648
|
+
paddingLeft: `calc(${SIZE.controlIcon} + ${SPACE.S2} - ${SPACE.S2})`,
|
|
1634
1649
|
minWidth: 0
|
|
1635
1650
|
},
|
|
1636
|
-
|
|
1651
|
+
// When hideName=true (popup mode), only the actions render. The
|
|
1652
|
+
// popup's own title bar carries the name + meta above this row, so
|
|
1653
|
+
// the actions land flush-left here — pinning them to the right
|
|
1654
|
+
// edge would leave the whole left half of the strip awkwardly
|
|
1655
|
+
// empty (the meta that used to fill it now lives in the title bar).
|
|
1656
|
+
actionsOnlyRow: {
|
|
1637
1657
|
display: "flex",
|
|
1638
|
-
|
|
1639
|
-
gap: "2px",
|
|
1658
|
+
justifyContent: "flex-start",
|
|
1640
1659
|
minWidth: 0
|
|
1641
1660
|
},
|
|
1642
|
-
|
|
1643
|
-
fontSize: "11px",
|
|
1644
|
-
fontWeight: FONT_WEIGHT.bold,
|
|
1645
|
-
letterSpacing: "0.06em",
|
|
1646
|
-
textTransform: "uppercase",
|
|
1647
|
-
color: COLOR.neutral500,
|
|
1648
|
-
whiteSpace: "nowrap"
|
|
1649
|
-
},
|
|
1650
|
-
metaValue: {
|
|
1661
|
+
metaText: {
|
|
1651
1662
|
fontSize: FONT_SIZE.sm,
|
|
1652
|
-
fontWeight: FONT_WEIGHT.
|
|
1653
|
-
color: COLOR.
|
|
1654
|
-
|
|
1663
|
+
fontWeight: FONT_WEIGHT.medium,
|
|
1664
|
+
color: COLOR.neutral600,
|
|
1665
|
+
lineHeight: LINE_HEIGHT.tight,
|
|
1655
1666
|
overflow: "hidden",
|
|
1656
1667
|
textOverflow: "ellipsis",
|
|
1657
|
-
|
|
1668
|
+
whiteSpace: "nowrap",
|
|
1669
|
+
minWidth: 0
|
|
1658
1670
|
},
|
|
1659
1671
|
actions: {
|
|
1660
1672
|
display: "flex",
|
|
@@ -1666,7 +1678,24 @@ var styles = {
|
|
|
1666
1678
|
alignItems: "center",
|
|
1667
1679
|
gap: SPACE.S2,
|
|
1668
1680
|
minHeight: SIZE.control,
|
|
1669
|
-
padding: `${SPACE.
|
|
1681
|
+
padding: `${SPACE.S1} ${SPACE.S3}`,
|
|
1682
|
+
fontSize: FONT_SIZE.sm,
|
|
1683
|
+
fontWeight: FONT_WEIGHT.semibold,
|
|
1684
|
+
color: COLOR.primary,
|
|
1685
|
+
backgroundColor: COLOR.white,
|
|
1686
|
+
border: `1.5px solid ${COLOR.primary}`,
|
|
1687
|
+
borderRadius: RADIUS.lg,
|
|
1688
|
+
cursor: "pointer"
|
|
1689
|
+
},
|
|
1690
|
+
// Sibling of the DICOM button — same shape so the two read as a pair.
|
|
1691
|
+
// Click hands off to the host's `onOpenCase` callback (role-aware
|
|
1692
|
+
// routing lives on the host side).
|
|
1693
|
+
openCaseButton: {
|
|
1694
|
+
display: "inline-flex",
|
|
1695
|
+
alignItems: "center",
|
|
1696
|
+
gap: SPACE.S2,
|
|
1697
|
+
minHeight: SIZE.control,
|
|
1698
|
+
padding: `${SPACE.S1} ${SPACE.S3}`,
|
|
1670
1699
|
fontSize: FONT_SIZE.sm,
|
|
1671
1700
|
fontWeight: FONT_WEIGHT.semibold,
|
|
1672
1701
|
color: COLOR.primary,
|
|
@@ -1675,10 +1704,8 @@ var styles = {
|
|
|
1675
1704
|
borderRadius: RADIUS.lg,
|
|
1676
1705
|
cursor: "pointer"
|
|
1677
1706
|
},
|
|
1678
|
-
// Channel-info button: people icon + participant count.
|
|
1679
|
-
// channel settings overlay
|
|
1680
|
-
// don't have to re-wire — the affordance just looks like a "members"
|
|
1681
|
-
// pill now instead of a gear).
|
|
1707
|
+
// Channel-info button: people icon + participant count. Opens the
|
|
1708
|
+
// channel settings overlay.
|
|
1682
1709
|
settingsIconButton: {
|
|
1683
1710
|
minHeight: SIZE.control,
|
|
1684
1711
|
display: "inline-flex",
|
|
@@ -2158,6 +2185,62 @@ function AlertIcon({ size = 14, color = "currentColor" }) {
|
|
|
2158
2185
|
}
|
|
2159
2186
|
);
|
|
2160
2187
|
}
|
|
2188
|
+
function RoleAvatarIcon({
|
|
2189
|
+
role,
|
|
2190
|
+
size = 18,
|
|
2191
|
+
color = "currentColor",
|
|
2192
|
+
className
|
|
2193
|
+
}) {
|
|
2194
|
+
const common = {
|
|
2195
|
+
width: size,
|
|
2196
|
+
height: size,
|
|
2197
|
+
viewBox: "0 0 24 24",
|
|
2198
|
+
fill: "none",
|
|
2199
|
+
stroke: color,
|
|
2200
|
+
strokeWidth: 1.9,
|
|
2201
|
+
strokeLinecap: "round",
|
|
2202
|
+
strokeLinejoin: "round",
|
|
2203
|
+
"aria-hidden": true,
|
|
2204
|
+
className
|
|
2205
|
+
};
|
|
2206
|
+
switch (role) {
|
|
2207
|
+
case "radiologist":
|
|
2208
|
+
return /* @__PURE__ */ jsxs("svg", { ...common, children: [
|
|
2209
|
+
/* @__PURE__ */ jsx("path", { d: "M7.5 8.5h9" }),
|
|
2210
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "9.5", r: "4" }),
|
|
2211
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "7.5", r: "1", fill: color, stroke: "none" }),
|
|
2212
|
+
/* @__PURE__ */ jsx("path", { d: "M4 21v-1.5a5 5 0 0 1 5-5h6a5 5 0 0 1 5 5V21" })
|
|
2213
|
+
] });
|
|
2214
|
+
case "lab":
|
|
2215
|
+
return /* @__PURE__ */ jsxs("svg", { ...common, children: [
|
|
2216
|
+
/* @__PURE__ */ jsx("path", { d: "M3 21V9l9-6 9 6v12" }),
|
|
2217
|
+
/* @__PURE__ */ jsx("path", { d: "M12 11v6" }),
|
|
2218
|
+
/* @__PURE__ */ jsx("path", { d: "M9 14h6" }),
|
|
2219
|
+
/* @__PURE__ */ jsx("path", { d: "M11 21v-3h2v3" }),
|
|
2220
|
+
/* @__PURE__ */ jsx("path", { d: "M3 21h18" })
|
|
2221
|
+
] });
|
|
2222
|
+
case "physician":
|
|
2223
|
+
return /* @__PURE__ */ jsxs("svg", { ...common, children: [
|
|
2224
|
+
/* @__PURE__ */ jsx("path", { d: "M7 3v5a4 4 0 0 0 8 0V3" }),
|
|
2225
|
+
/* @__PURE__ */ jsx("path", { d: "M5 3h2" }),
|
|
2226
|
+
/* @__PURE__ */ jsx("path", { d: "M15 3h2" }),
|
|
2227
|
+
/* @__PURE__ */ jsx("path", { d: "M11 12v3a5 5 0 0 0 5 5h0a5 5 0 0 0 5-5v-2" }),
|
|
2228
|
+
/* @__PURE__ */ jsx("circle", { cx: "21", cy: "11", r: "2" })
|
|
2229
|
+
] });
|
|
2230
|
+
case "admin":
|
|
2231
|
+
return /* @__PURE__ */ jsxs("svg", { ...common, children: [
|
|
2232
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" }),
|
|
2233
|
+
/* @__PURE__ */ jsx("path", { d: "M12 2v3" }),
|
|
2234
|
+
/* @__PURE__ */ jsx("path", { d: "M12 19v3" }),
|
|
2235
|
+
/* @__PURE__ */ jsx("path", { d: "M5 12H2" }),
|
|
2236
|
+
/* @__PURE__ */ jsx("path", { d: "M22 12h-3" }),
|
|
2237
|
+
/* @__PURE__ */ jsx("path", { d: "M5.6 5.6l2 2" }),
|
|
2238
|
+
/* @__PURE__ */ jsx("path", { d: "M16.4 16.4l2 2" }),
|
|
2239
|
+
/* @__PURE__ */ jsx("path", { d: "M5.6 18.4l2-2" }),
|
|
2240
|
+
/* @__PURE__ */ jsx("path", { d: "M16.4 7.6l2-2" })
|
|
2241
|
+
] });
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2161
2244
|
function Spinner({ size = 16, color = COLOR.neutral500, thickness = 2 }) {
|
|
2162
2245
|
return /* @__PURE__ */ jsx(
|
|
2163
2246
|
"span",
|
|
@@ -2246,12 +2329,11 @@ function MessageBubble({
|
|
|
2246
2329
|
...styles5.authorAvatar,
|
|
2247
2330
|
backgroundColor: roleColor(message.senderRole)
|
|
2248
2331
|
},
|
|
2249
|
-
"aria-
|
|
2250
|
-
children:
|
|
2332
|
+
"aria-label": ROLE_LABELS[message.senderRole] ?? message.senderRole,
|
|
2333
|
+
children: /* @__PURE__ */ jsx(RoleAvatarIcon, { role: message.senderRole, size: 20, color: COLOR.white })
|
|
2251
2334
|
}
|
|
2252
2335
|
),
|
|
2253
|
-
/* @__PURE__ */ jsx("span", { style: styles5.authorName, children: message.senderName })
|
|
2254
|
-
/* @__PURE__ */ jsx(RoleBadge, { role: message.senderRole })
|
|
2336
|
+
/* @__PURE__ */ jsx("span", { style: styles5.authorName, children: message.senderName })
|
|
2255
2337
|
] }),
|
|
2256
2338
|
/* @__PURE__ */ jsxs(
|
|
2257
2339
|
"div",
|
|
@@ -2326,9 +2408,6 @@ function MessageBubble({
|
|
|
2326
2408
|
}
|
|
2327
2409
|
);
|
|
2328
2410
|
}
|
|
2329
|
-
function computeInitials(name) {
|
|
2330
|
-
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((p) => p[0]?.toUpperCase() ?? "").join("") || "?";
|
|
2331
|
-
}
|
|
2332
2411
|
function roleColor(role) {
|
|
2333
2412
|
switch (role) {
|
|
2334
2413
|
case "radiologist":
|
|
@@ -2413,9 +2492,6 @@ function SystemBubble({ message }) {
|
|
|
2413
2492
|
/* @__PURE__ */ jsx("span", { style: styles5.systemTime, children: formatTime(message.insertedAt) })
|
|
2414
2493
|
] }) });
|
|
2415
2494
|
}
|
|
2416
|
-
function RoleBadge({ role }) {
|
|
2417
|
-
return /* @__PURE__ */ jsx("span", { style: { ...styles5.roleBadge, backgroundColor: roleColor(role) }, children: ROLE_LABELS[role] ?? role });
|
|
2418
|
-
}
|
|
2419
2495
|
function formatTime(iso) {
|
|
2420
2496
|
try {
|
|
2421
2497
|
return new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
@@ -2517,16 +2593,6 @@ var styles5 = {
|
|
|
2517
2593
|
color: "#fff4d6",
|
|
2518
2594
|
backgroundColor: "rgba(255, 255, 255, 0.2)"
|
|
2519
2595
|
},
|
|
2520
|
-
roleBadge: {
|
|
2521
|
-
fontSize: "10px",
|
|
2522
|
-
fontWeight: FONT_WEIGHT.bold,
|
|
2523
|
-
padding: "2px 7px",
|
|
2524
|
-
borderRadius: RADIUS.sm,
|
|
2525
|
-
textTransform: "uppercase",
|
|
2526
|
-
letterSpacing: "0.06em",
|
|
2527
|
-
color: COLOR.white,
|
|
2528
|
-
flexShrink: 0
|
|
2529
|
-
},
|
|
2530
2596
|
textBody: {
|
|
2531
2597
|
margin: 0,
|
|
2532
2598
|
fontSize: FONT_SIZE.md,
|
|
@@ -2990,9 +3056,6 @@ var styles6 = {
|
|
|
2990
3056
|
alignItems: "center",
|
|
2991
3057
|
gap: SPACE.S3,
|
|
2992
3058
|
margin: `${SPACE.S4} 0 ${SPACE.S3}`,
|
|
2993
|
-
position: "sticky",
|
|
2994
|
-
top: SPACE.S1,
|
|
2995
|
-
zIndex: Z_INDEX.sticky,
|
|
2996
3059
|
pointerEvents: "none"
|
|
2997
3060
|
},
|
|
2998
3061
|
dayHr: {
|
|
@@ -3007,11 +3070,7 @@ var styles6 = {
|
|
|
3007
3070
|
color: COLOR.neutral500,
|
|
3008
3071
|
textTransform: "uppercase",
|
|
3009
3072
|
letterSpacing: "0.06em",
|
|
3010
|
-
// Subtle pill background so the label is readable when it overlays
|
|
3011
|
-
// bubbles passing under it during sticky scroll. Without this the
|
|
3012
|
-
// hairlines visually run through the text on tinted backgrounds.
|
|
3013
3073
|
padding: `2px ${SPACE.S2}`,
|
|
3014
|
-
backgroundColor: COLOR.white,
|
|
3015
3074
|
borderRadius: RADIUS.sm
|
|
3016
3075
|
},
|
|
3017
3076
|
bubbleSlot: {
|
|
@@ -3309,7 +3368,7 @@ function MessageInput({
|
|
|
3309
3368
|
style: styles8.textarea
|
|
3310
3369
|
}
|
|
3311
3370
|
),
|
|
3312
|
-
/* @__PURE__ */
|
|
3371
|
+
/* @__PURE__ */ jsx(
|
|
3313
3372
|
"button",
|
|
3314
3373
|
{
|
|
3315
3374
|
onClick: handleSendText,
|
|
@@ -3321,10 +3380,7 @@ function MessageInput({
|
|
|
3321
3380
|
opacity: text.trim() ? 1 : 0.5
|
|
3322
3381
|
},
|
|
3323
3382
|
type: "button",
|
|
3324
|
-
children:
|
|
3325
|
-
/* @__PURE__ */ jsx(SendIcon, { size: 20, color: COLOR.white }),
|
|
3326
|
-
/* @__PURE__ */ jsx("span", { style: styles8.sendLabel, children: "Send" })
|
|
3327
|
-
]
|
|
3383
|
+
children: /* @__PURE__ */ jsx(SendIcon, { size: 20, color: COLOR.white })
|
|
3328
3384
|
}
|
|
3329
3385
|
)
|
|
3330
3386
|
] })
|
|
@@ -3422,29 +3478,33 @@ var styles8 = {
|
|
|
3422
3478
|
fontFamily: "inherit",
|
|
3423
3479
|
transition: "background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease"
|
|
3424
3480
|
},
|
|
3425
|
-
//
|
|
3426
|
-
//
|
|
3481
|
+
// Square icon-only send button. The arrow inside an obvious input
|
|
3482
|
+
// context is affordance enough; the word "Send" used to sit next to
|
|
3483
|
+
// it but added clutter without disambiguating anything.
|
|
3427
3484
|
sendButton: {
|
|
3428
3485
|
display: "inline-flex",
|
|
3429
3486
|
alignItems: "center",
|
|
3430
|
-
|
|
3431
|
-
|
|
3487
|
+
justifyContent: "center",
|
|
3488
|
+
width: "48px",
|
|
3432
3489
|
height: "48px",
|
|
3433
|
-
padding: `0 ${SPACE.S4}`,
|
|
3434
3490
|
backgroundColor: COLOR.primary,
|
|
3435
3491
|
color: COLOR.white,
|
|
3436
3492
|
border: "none",
|
|
3437
3493
|
borderRadius: "14px",
|
|
3438
3494
|
cursor: "pointer",
|
|
3439
3495
|
flexShrink: 0,
|
|
3440
|
-
fontFamily: "inherit",
|
|
3441
|
-
fontSize: "15px",
|
|
3442
|
-
fontWeight: FONT_WEIGHT.semibold,
|
|
3443
3496
|
transition: "opacity 120ms ease, background-color 120ms ease"
|
|
3444
|
-
},
|
|
3445
|
-
sendLabel: {
|
|
3446
|
-
lineHeight: 1
|
|
3447
3497
|
}};
|
|
3498
|
+
var ROLE_AVATAR_BG = {
|
|
3499
|
+
radiologist: "#4f46e5",
|
|
3500
|
+
// indigo
|
|
3501
|
+
lab: "#2563eb",
|
|
3502
|
+
// brand blue
|
|
3503
|
+
physician: "#0284c7",
|
|
3504
|
+
// sky
|
|
3505
|
+
admin: "#64748b"
|
|
3506
|
+
// slate
|
|
3507
|
+
};
|
|
3448
3508
|
function ParticipantsList({
|
|
3449
3509
|
participants,
|
|
3450
3510
|
currentUserId,
|
|
@@ -3454,7 +3514,17 @@ function ParticipantsList({
|
|
|
3454
3514
|
}) {
|
|
3455
3515
|
return /* @__PURE__ */ jsx("div", { className, style: styles9.list, children: participants.map((participant) => /* @__PURE__ */ jsxs("div", { style: styles9.item, children: [
|
|
3456
3516
|
/* @__PURE__ */ jsxs("div", { style: styles9.avatar, children: [
|
|
3457
|
-
participant.avatar ? /* @__PURE__ */ jsx("img", { src: participant.avatar, alt: "", style: styles9.avatarImg }) : /* @__PURE__ */ jsx(
|
|
3517
|
+
participant.avatar ? /* @__PURE__ */ jsx("img", { src: participant.avatar, alt: "", style: styles9.avatarImg }) : /* @__PURE__ */ jsx(
|
|
3518
|
+
"span",
|
|
3519
|
+
{
|
|
3520
|
+
style: {
|
|
3521
|
+
...styles9.avatarFallback,
|
|
3522
|
+
backgroundColor: ROLE_AVATAR_BG[participant.userRole]
|
|
3523
|
+
},
|
|
3524
|
+
"aria-hidden": "true",
|
|
3525
|
+
children: /* @__PURE__ */ jsx(RoleAvatarIcon, { role: participant.userRole, size: 18, color: COLOR.white })
|
|
3526
|
+
}
|
|
3527
|
+
),
|
|
3458
3528
|
/* @__PURE__ */ jsx(
|
|
3459
3529
|
"span",
|
|
3460
3530
|
{
|
|
@@ -3470,7 +3540,7 @@ function ParticipantsList({
|
|
|
3470
3540
|
participant.userName ?? fallbackName(participant.userRole),
|
|
3471
3541
|
participant.userId === currentUserId && /* @__PURE__ */ jsx("span", { style: styles9.youBadge, children: " (you)" })
|
|
3472
3542
|
] }),
|
|
3473
|
-
/* @__PURE__ */ jsx(
|
|
3543
|
+
/* @__PURE__ */ jsx(RoleBadge, { role: participant.userRole })
|
|
3474
3544
|
] }),
|
|
3475
3545
|
isAdmin && participant.userId !== currentUserId && /* @__PURE__ */ jsx(
|
|
3476
3546
|
"button",
|
|
@@ -3498,7 +3568,7 @@ function fallbackName(role) {
|
|
|
3498
3568
|
return "User";
|
|
3499
3569
|
}
|
|
3500
3570
|
}
|
|
3501
|
-
function
|
|
3571
|
+
function RoleBadge({ role }) {
|
|
3502
3572
|
const colors = {
|
|
3503
3573
|
radiologist: { bg: "#eef2ff", text: "#4f46e5" },
|
|
3504
3574
|
// indigo
|
|
@@ -3540,13 +3610,10 @@ var styles9 = {
|
|
|
3540
3610
|
width: "32px",
|
|
3541
3611
|
height: "32px",
|
|
3542
3612
|
borderRadius: RADIUS.full,
|
|
3543
|
-
backgroundColor: COLOR.neutral200,
|
|
3544
3613
|
display: "flex",
|
|
3545
3614
|
alignItems: "center",
|
|
3546
3615
|
justifyContent: "center",
|
|
3547
|
-
|
|
3548
|
-
fontWeight: FONT_WEIGHT.semibold,
|
|
3549
|
-
color: COLOR.neutral500
|
|
3616
|
+
color: COLOR.white
|
|
3550
3617
|
},
|
|
3551
3618
|
statusDot: {
|
|
3552
3619
|
position: "absolute",
|
|
@@ -4138,6 +4205,7 @@ function CollabPanel({
|
|
|
4138
4205
|
showSeenBy = true,
|
|
4139
4206
|
onBack,
|
|
4140
4207
|
hidePatientName = false,
|
|
4208
|
+
hideOpenCase = false,
|
|
4141
4209
|
onConversationChange,
|
|
4142
4210
|
themeMode = "light",
|
|
4143
4211
|
className,
|
|
@@ -4180,6 +4248,7 @@ function CollabPanel({
|
|
|
4180
4248
|
config.onOpenDicom(patientData.studyId, patientData.storageId);
|
|
4181
4249
|
}
|
|
4182
4250
|
};
|
|
4251
|
+
const handleOpenCase = !hideOpenCase && config.onOpenCase ? () => config.onOpenCase?.(patientData.orderId, patientData.displayOrderId) : void 0;
|
|
4183
4252
|
const handleJumpToMessage = (messageId) => {
|
|
4184
4253
|
messageListRef.current?.scrollToMessage(messageId);
|
|
4185
4254
|
};
|
|
@@ -4255,6 +4324,7 @@ function CollabPanel({
|
|
|
4255
4324
|
patientData,
|
|
4256
4325
|
participants,
|
|
4257
4326
|
onOpenDicom: handleOpenDicom,
|
|
4327
|
+
onOpenCase: handleOpenCase,
|
|
4258
4328
|
onOpenSettings: () => setShowSettings(true),
|
|
4259
4329
|
onBack,
|
|
4260
4330
|
hideName: hidePatientName,
|
|
@@ -4509,14 +4579,16 @@ function CollabPopup({
|
|
|
4509
4579
|
),
|
|
4510
4580
|
/* @__PURE__ */ jsxs("div", { style: styles13.titleCenter, children: [
|
|
4511
4581
|
/* @__PURE__ */ jsx("h2", { id: titleId, style: styles13.patientName, children: patientData.patientName || titleText }),
|
|
4512
|
-
(
|
|
4513
|
-
|
|
4514
|
-
patientData.
|
|
4515
|
-
patientData.
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4582
|
+
(() => {
|
|
4583
|
+
const parts = [];
|
|
4584
|
+
if (patientData.patientAge) parts.push(String(patientData.patientAge));
|
|
4585
|
+
if (patientData.patientSex) parts.push(String(patientData.patientSex));
|
|
4586
|
+
if (patientData.studyType) parts.push(patientData.studyType);
|
|
4587
|
+
if (patientData.bodyParts && patientData.bodyParts.length > 0) {
|
|
4588
|
+
parts.push(patientData.bodyParts.join(", "));
|
|
4589
|
+
}
|
|
4590
|
+
return parts.length > 0 ? /* @__PURE__ */ jsx("div", { style: styles13.subRow, children: /* @__PURE__ */ jsx("span", { style: styles13.metaText, children: parts.join(" \xB7 ") }) }) : null;
|
|
4591
|
+
})()
|
|
4520
4592
|
] }),
|
|
4521
4593
|
/* @__PURE__ */ jsxs("div", { style: styles13.titleActions, children: [
|
|
4522
4594
|
/* @__PURE__ */ jsx(
|
|
@@ -4605,19 +4677,17 @@ var styles13 = {
|
|
|
4605
4677
|
subRow: {
|
|
4606
4678
|
display: "flex",
|
|
4607
4679
|
alignItems: "center",
|
|
4608
|
-
gap: SPACE.S2,
|
|
4609
4680
|
fontSize: FONT_SIZE.sm,
|
|
4610
4681
|
color: COLOR.neutral500,
|
|
4611
4682
|
overflow: "hidden",
|
|
4612
4683
|
textOverflow: "ellipsis",
|
|
4613
4684
|
whiteSpace: "nowrap"
|
|
4614
4685
|
},
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
fontVariantNumeric: "tabular-nums"
|
|
4686
|
+
metaText: {
|
|
4687
|
+
overflow: "hidden",
|
|
4688
|
+
textOverflow: "ellipsis",
|
|
4689
|
+
whiteSpace: "nowrap",
|
|
4690
|
+
minWidth: 0
|
|
4621
4691
|
},
|
|
4622
4692
|
titleActions: {
|
|
4623
4693
|
display: "flex",
|
|
@@ -5430,7 +5500,7 @@ function ConversationListItem({
|
|
|
5430
5500
|
const studyType = item.patientSnapshot?.studyType;
|
|
5431
5501
|
const patientId = item.patientSnapshot?.patientId;
|
|
5432
5502
|
const showStudyRow = !!(studyType || patientId);
|
|
5433
|
-
const initials =
|
|
5503
|
+
const initials = computeInitials(item.patientSnapshot?.patientName || displayName);
|
|
5434
5504
|
return /* @__PURE__ */ jsxs(
|
|
5435
5505
|
"button",
|
|
5436
5506
|
{
|
|
@@ -5525,7 +5595,7 @@ function previewText(message) {
|
|
|
5525
5595
|
}
|
|
5526
5596
|
}
|
|
5527
5597
|
}
|
|
5528
|
-
function
|
|
5598
|
+
function computeInitials(name) {
|
|
5529
5599
|
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase() ?? "").join("") || "?";
|
|
5530
5600
|
}
|
|
5531
5601
|
var styles15 = {
|