@natoe/colab 0.1.23 → 0.1.26

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 CHANGED
@@ -88,6 +88,19 @@ interface CollabConfig {
88
88
  onUploadFile?: (file: File | Blob, fileName?: string) => Promise<string>;
89
89
  onDeepLink?: (path: string) => void;
90
90
  onError?: (error: CollabError) => void;
91
+ /**
92
+ * Report a message. The host captures any reason UI and calls its backend.
93
+ * The "Report" message action renders only when this callback is provided.
94
+ */
95
+ onReportMessage?: (message: Message) => void | Promise<void>;
96
+ /**
97
+ * Block a user. The "Block" action renders only when this callback is set.
98
+ */
99
+ onBlockUser?: (userId: string, userName: string) => void | Promise<void>;
100
+ /** Unblock a previously blocked user. */
101
+ onUnblockUser?: (userId: string) => void | Promise<void>;
102
+ /** IDs of users the current user has blocked — their messages are hidden. */
103
+ blockedUserIds?: string[];
91
104
  }
92
105
  type UserRole = 'lab' | 'radiologist' | 'physician' | 'admin';
93
106
  interface PatientData {
@@ -932,6 +945,12 @@ interface MessageListProps {
932
945
  onPin?: (messageId: string) => void;
933
946
  onUnpin?: (messageId: string) => void;
934
947
  onCopy?: (text: string) => void;
948
+ /** Report a message (moderation). Shown only for others' messages. */
949
+ onReport?: (message: Message) => void;
950
+ /** Block a message's sender (moderation). Shown only for others' messages. */
951
+ onBlock?: (message: Message) => void;
952
+ /** Sender IDs to hide locally (blocked users). */
953
+ blockedUserIds?: string[];
935
954
  /** Retry a failed message (own bubbles only) */
936
955
  onRetry?: (messageId: string) => void;
937
956
  pinDisabled?: boolean;
@@ -953,6 +972,10 @@ interface MessageBubbleProps {
953
972
  onPin?: (messageId: string) => void;
954
973
  onUnpin?: (messageId: string) => void;
955
974
  onCopy?: (text: string) => void;
975
+ /** Report this message (moderation). Only shown for others' messages. */
976
+ onReport?: (message: Message) => void;
977
+ /** Block this message's sender (moderation). Only shown for others' messages. */
978
+ onBlock?: (message: Message) => void;
956
979
  onReplyJumpTo?: (messageId: string) => void;
957
980
  /** Re-send a previously-failed message (own bubbles only) */
958
981
  onRetry?: (messageId: string) => void;
@@ -960,7 +983,7 @@ interface MessageBubbleProps {
960
983
  pinDisabled?: boolean;
961
984
  className?: string;
962
985
  }
963
- declare function MessageBubble({ message, isOwn, participants, currentUserId, showSeenBy, onDeepLinkClick, onReply, onPin, onUnpin, onCopy, onReplyJumpTo, onRetry, pinDisabled, className, }: MessageBubbleProps): react_jsx_runtime.JSX.Element;
986
+ declare function MessageBubble({ message, isOwn, participants, currentUserId, showSeenBy, onDeepLinkClick, onReply, onPin, onUnpin, onCopy, onReport, onBlock, onReplyJumpTo, onRetry, pinDisabled, className, }: MessageBubbleProps): react_jsx_runtime.JSX.Element;
964
987
 
965
988
  interface MessageInputProps {
966
989
  onSendText: (body: string) => Promise<void>;
@@ -984,6 +1007,12 @@ interface MessageActionsMenuProps {
984
1007
  onPin: (messageId: string) => void;
985
1008
  onUnpin: (messageId: string) => void;
986
1009
  onCopy?: (text: string) => void;
1010
+ /** Report this message (moderation). Rendered only when `canModerate`. */
1011
+ onReport?: (message: Message) => void;
1012
+ /** Block this message's sender (moderation). Rendered only when `canModerate`. */
1013
+ onBlock?: (message: Message) => void;
1014
+ /** Enable moderation actions (Report / Block) — true for others' messages. */
1015
+ canModerate?: boolean;
987
1016
  /** Whether we've hit the pin limit — if true, pin is disabled */
988
1017
  pinDisabled?: boolean;
989
1018
  /** Anchor the popover to the right edge of the trigger (use for messages on the left side of the panel) */
@@ -998,7 +1027,7 @@ interface MessageActionsMenuProps {
998
1027
  *
999
1028
  * Closes on outside-click, Escape, window resize, or scroll outside the menu.
1000
1029
  */
1001
- declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
1030
+ declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, onReport, onBlock, canModerate, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
1002
1031
 
1003
1032
  interface ReplyPreviewProps {
1004
1033
  /** The message being replied to */
package/dist/index.d.ts CHANGED
@@ -88,6 +88,19 @@ interface CollabConfig {
88
88
  onUploadFile?: (file: File | Blob, fileName?: string) => Promise<string>;
89
89
  onDeepLink?: (path: string) => void;
90
90
  onError?: (error: CollabError) => void;
91
+ /**
92
+ * Report a message. The host captures any reason UI and calls its backend.
93
+ * The "Report" message action renders only when this callback is provided.
94
+ */
95
+ onReportMessage?: (message: Message) => void | Promise<void>;
96
+ /**
97
+ * Block a user. The "Block" action renders only when this callback is set.
98
+ */
99
+ onBlockUser?: (userId: string, userName: string) => void | Promise<void>;
100
+ /** Unblock a previously blocked user. */
101
+ onUnblockUser?: (userId: string) => void | Promise<void>;
102
+ /** IDs of users the current user has blocked — their messages are hidden. */
103
+ blockedUserIds?: string[];
91
104
  }
92
105
  type UserRole = 'lab' | 'radiologist' | 'physician' | 'admin';
93
106
  interface PatientData {
@@ -932,6 +945,12 @@ interface MessageListProps {
932
945
  onPin?: (messageId: string) => void;
933
946
  onUnpin?: (messageId: string) => void;
934
947
  onCopy?: (text: string) => void;
948
+ /** Report a message (moderation). Shown only for others' messages. */
949
+ onReport?: (message: Message) => void;
950
+ /** Block a message's sender (moderation). Shown only for others' messages. */
951
+ onBlock?: (message: Message) => void;
952
+ /** Sender IDs to hide locally (blocked users). */
953
+ blockedUserIds?: string[];
935
954
  /** Retry a failed message (own bubbles only) */
936
955
  onRetry?: (messageId: string) => void;
937
956
  pinDisabled?: boolean;
@@ -953,6 +972,10 @@ interface MessageBubbleProps {
953
972
  onPin?: (messageId: string) => void;
954
973
  onUnpin?: (messageId: string) => void;
955
974
  onCopy?: (text: string) => void;
975
+ /** Report this message (moderation). Only shown for others' messages. */
976
+ onReport?: (message: Message) => void;
977
+ /** Block this message's sender (moderation). Only shown for others' messages. */
978
+ onBlock?: (message: Message) => void;
956
979
  onReplyJumpTo?: (messageId: string) => void;
957
980
  /** Re-send a previously-failed message (own bubbles only) */
958
981
  onRetry?: (messageId: string) => void;
@@ -960,7 +983,7 @@ interface MessageBubbleProps {
960
983
  pinDisabled?: boolean;
961
984
  className?: string;
962
985
  }
963
- declare function MessageBubble({ message, isOwn, participants, currentUserId, showSeenBy, onDeepLinkClick, onReply, onPin, onUnpin, onCopy, onReplyJumpTo, onRetry, pinDisabled, className, }: MessageBubbleProps): react_jsx_runtime.JSX.Element;
986
+ declare function MessageBubble({ message, isOwn, participants, currentUserId, showSeenBy, onDeepLinkClick, onReply, onPin, onUnpin, onCopy, onReport, onBlock, onReplyJumpTo, onRetry, pinDisabled, className, }: MessageBubbleProps): react_jsx_runtime.JSX.Element;
964
987
 
965
988
  interface MessageInputProps {
966
989
  onSendText: (body: string) => Promise<void>;
@@ -984,6 +1007,12 @@ interface MessageActionsMenuProps {
984
1007
  onPin: (messageId: string) => void;
985
1008
  onUnpin: (messageId: string) => void;
986
1009
  onCopy?: (text: string) => void;
1010
+ /** Report this message (moderation). Rendered only when `canModerate`. */
1011
+ onReport?: (message: Message) => void;
1012
+ /** Block this message's sender (moderation). Rendered only when `canModerate`. */
1013
+ onBlock?: (message: Message) => void;
1014
+ /** Enable moderation actions (Report / Block) — true for others' messages. */
1015
+ canModerate?: boolean;
987
1016
  /** Whether we've hit the pin limit — if true, pin is disabled */
988
1017
  pinDisabled?: boolean;
989
1018
  /** Anchor the popover to the right edge of the trigger (use for messages on the left side of the panel) */
@@ -998,7 +1027,7 @@ interface MessageActionsMenuProps {
998
1027
  *
999
1028
  * Closes on outside-click, Escape, window resize, or scroll outside the menu.
1000
1029
  */
1001
- declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
1030
+ declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, onReport, onBlock, canModerate, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
1002
1031
 
1003
1032
  interface ReplyPreviewProps {
1004
1033
  /** The message being replied to */
package/dist/index.js CHANGED
@@ -1948,6 +1948,20 @@ function MoreIcon({ size = 18, color = "currentColor" }) {
1948
1948
  }
1949
1949
  );
1950
1950
  }
1951
+ function AlertIcon({ size = 14, color = "currentColor" }) {
1952
+ return /* @__PURE__ */ jsxRuntime.jsx(
1953
+ "svg",
1954
+ {
1955
+ xmlns: "http://www.w3.org/2000/svg",
1956
+ width: size,
1957
+ height: size,
1958
+ viewBox: "0 0 24 24",
1959
+ fill: color,
1960
+ "aria-hidden": "true",
1961
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" })
1962
+ }
1963
+ );
1964
+ }
1951
1965
  var VIEWPORT_MARGIN = 8;
1952
1966
  var TRIGGER_GAP = 4;
1953
1967
  function MessageActionsMenu({
@@ -1956,6 +1970,9 @@ function MessageActionsMenu({
1956
1970
  onPin,
1957
1971
  onUnpin,
1958
1972
  onCopy,
1973
+ onReport,
1974
+ onBlock,
1975
+ canModerate = false,
1959
1976
  pinDisabled = false,
1960
1977
  anchorRight = false,
1961
1978
  className
@@ -2094,6 +2111,36 @@ function MessageActionsMenu({
2094
2111
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Copy text" })
2095
2112
  ]
2096
2113
  }
2114
+ ),
2115
+ canModerate && (onReport || onBlock) && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.divider }),
2116
+ canModerate && onReport && /* @__PURE__ */ jsxRuntime.jsxs(
2117
+ "button",
2118
+ {
2119
+ type: "button",
2120
+ role: "menuitem",
2121
+ onClick: () => run(() => onReport(message)),
2122
+ style: styles4.item,
2123
+ children: [
2124
+ /* @__PURE__ */ jsxRuntime.jsx(AlertIcon, { size: 16, color: COLOR.neutral700 }),
2125
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Report message" })
2126
+ ]
2127
+ }
2128
+ ),
2129
+ canModerate && onBlock && /* @__PURE__ */ jsxRuntime.jsxs(
2130
+ "button",
2131
+ {
2132
+ type: "button",
2133
+ role: "menuitem",
2134
+ onClick: () => run(() => onBlock(message)),
2135
+ style: { ...styles4.item, ...styles4.itemDanger },
2136
+ children: [
2137
+ /* @__PURE__ */ jsxRuntime.jsx(AlertIcon, { size: 16, color: "#c0392b" }),
2138
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2139
+ "Block ",
2140
+ message.senderName
2141
+ ] })
2142
+ ]
2143
+ }
2097
2144
  )
2098
2145
  ]
2099
2146
  }
@@ -2172,6 +2219,14 @@ var styles4 = {
2172
2219
  itemDisabled: {
2173
2220
  color: COLOR.neutral400,
2174
2221
  cursor: "not-allowed"
2222
+ },
2223
+ itemDanger: {
2224
+ color: "#c0392b"
2225
+ },
2226
+ divider: {
2227
+ height: "1px",
2228
+ backgroundColor: COLOR.neutral200,
2229
+ margin: "4px 0"
2175
2230
  }
2176
2231
  };
2177
2232
  function FileIcon({ size = 18, color = "currentColor" }) {
@@ -2188,20 +2243,6 @@ function FileIcon({ size = 18, color = "currentColor" }) {
2188
2243
  }
2189
2244
  );
2190
2245
  }
2191
- function AlertIcon({ size = 14, color = "currentColor" }) {
2192
- return /* @__PURE__ */ jsxRuntime.jsx(
2193
- "svg",
2194
- {
2195
- xmlns: "http://www.w3.org/2000/svg",
2196
- width: size,
2197
- height: size,
2198
- viewBox: "0 0 24 24",
2199
- fill: color,
2200
- "aria-hidden": "true",
2201
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" })
2202
- }
2203
- );
2204
- }
2205
2246
  function RoleAvatarIcon({
2206
2247
  role,
2207
2248
  size = 18,
@@ -2303,6 +2344,8 @@ function MessageBubble({
2303
2344
  onPin,
2304
2345
  onUnpin,
2305
2346
  onCopy,
2347
+ onReport,
2348
+ onBlock,
2306
2349
  onReplyJumpTo,
2307
2350
  onRetry,
2308
2351
  pinDisabled = false,
@@ -2311,7 +2354,8 @@ function MessageBubble({
2311
2354
  if (message.type === "system") {
2312
2355
  return /* @__PURE__ */ jsxRuntime.jsx(SystemBubble, { message });
2313
2356
  }
2314
- const hasActions = !!(onReply || onPin || onUnpin || onCopy);
2357
+ const canModerate = !isOwn && !!(onReport || onBlock);
2358
+ const hasActions = !!(onReply || onPin || onUnpin || onCopy) || canModerate;
2315
2359
  const actionsSlot = hasActions ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.actionsSlot, children: /* @__PURE__ */ jsxRuntime.jsx(
2316
2360
  MessageActionsMenu,
2317
2361
  {
@@ -2323,6 +2367,9 @@ function MessageBubble({
2323
2367
  onUnpin: onUnpin ?? (() => {
2324
2368
  }),
2325
2369
  onCopy,
2370
+ onReport,
2371
+ onBlock,
2372
+ canModerate,
2326
2373
  pinDisabled,
2327
2374
  anchorRight: !isOwn
2328
2375
  }
@@ -2859,6 +2906,9 @@ var MessageList = React4.forwardRef(function MessageList2({
2859
2906
  onPin,
2860
2907
  onUnpin,
2861
2908
  onCopy,
2909
+ onReport,
2910
+ onBlock,
2911
+ blockedUserIds,
2862
2912
  onRetry,
2863
2913
  pinDisabled,
2864
2914
  className
@@ -2962,7 +3012,7 @@ var MessageList = React4.forwardRef(function MessageList2({
2962
3012
  messages.length === 0 && isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.firstLoad, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: 20 }) }),
2963
3013
  (() => {
2964
3014
  let lastValidBucket = null;
2965
- return messages.map((message) => {
3015
+ return messages.filter((m) => !blockedUserIds?.includes(m.senderId)).map((message) => {
2966
3016
  const currentBucket = dayBucketKey(message.insertedAt);
2967
3017
  const showDivider = !!currentBucket && currentBucket !== lastValidBucket;
2968
3018
  if (currentBucket) lastValidBucket = currentBucket;
@@ -2985,6 +3035,8 @@ var MessageList = React4.forwardRef(function MessageList2({
2985
3035
  onPin,
2986
3036
  onUnpin,
2987
3037
  onCopy,
3038
+ onReport,
3039
+ onBlock,
2988
3040
  onRetry,
2989
3041
  pinDisabled
2990
3042
  }
@@ -4604,6 +4656,9 @@ function CollabPanel({
4604
4656
  onPin: handlePin,
4605
4657
  onUnpin: handleUnpin,
4606
4658
  onCopy: handleCopy,
4659
+ onReport: config.onReportMessage ? (m) => config.onReportMessage(m) : void 0,
4660
+ onBlock: config.onBlockUser ? (m) => config.onBlockUser(m.senderId, m.senderName) : void 0,
4661
+ blockedUserIds: config.blockedUserIds,
4607
4662
  onRetry: retryMessage,
4608
4663
  pinDisabled
4609
4664
  }
@@ -5559,7 +5614,7 @@ var styles14 = {
5559
5614
  },
5560
5615
  messageRow: {
5561
5616
  display: "flex",
5562
- alignItems: "center",
5617
+ alignItems: "flex-start",
5563
5618
  gap: SPACE.S2,
5564
5619
  fontSize: FONT_SIZE.xs,
5565
5620
  lineHeight: LINE_HEIGHT.normal,
@@ -5569,7 +5624,8 @@ var styles14 = {
5569
5624
  flexShrink: 0,
5570
5625
  width: "6px",
5571
5626
  height: "6px",
5572
- borderRadius: RADIUS.full
5627
+ borderRadius: RADIUS.full,
5628
+ marginTop: "7px"
5573
5629
  },
5574
5630
  senderName: {
5575
5631
  flexShrink: 0,
@@ -5578,9 +5634,11 @@ var styles14 = {
5578
5634
  },
5579
5635
  messageText: {
5580
5636
  color: COLOR.neutral600,
5637
+ display: "-webkit-box",
5638
+ WebkitLineClamp: 2,
5639
+ WebkitBoxOrient: "vertical",
5581
5640
  overflow: "hidden",
5582
- textOverflow: "ellipsis",
5583
- whiteSpace: "nowrap",
5641
+ wordBreak: "break-word",
5584
5642
  minWidth: 0,
5585
5643
  flex: 1
5586
5644
  },