@adatechnology/conversations-ui 0.5.0 → 0.6.0

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.
Files changed (50) hide show
  1. package/README.md +82 -20
  2. package/dist/{chunk-JXJCPN34.js → chunk-FAQLC3TX.js} +1 -1
  3. package/dist/{chunk-RJMSM3YA.js → chunk-O6457XHK.js} +17 -11
  4. package/dist/chunk-OVFCLRQQ.js +84 -0
  5. package/dist/index.d.ts +14 -4
  6. package/dist/index.js +3 -3
  7. package/dist/participant/index.d.ts +25 -1
  8. package/dist/participant/index.js +454 -194
  9. package/dist/preview/index.js +2 -2
  10. package/dist/styles.css +98 -0
  11. package/package.json +2 -2
  12. package/src/MessageBubble.test.tsx +2 -2
  13. package/src/MessageText.test.tsx +27 -10
  14. package/src/MessageText.tsx +25 -17
  15. package/src/MessageTextCopiedBadge.tsx +10 -2
  16. package/src/StatusTicks.test.tsx +27 -6
  17. package/src/StatusTicks.tsx +30 -15
  18. package/src/legacyChannels.golden.test.ts +89 -0
  19. package/src/legacyDefaults.golden.test.tsx +127 -0
  20. package/src/legacyStyles.fixture.css +1121 -0
  21. package/src/legacyStyles.golden.test.ts +121 -0
  22. package/src/messageTextCopyInteraction.test.ts +75 -0
  23. package/src/messageTextCopyInteraction.ts +37 -0
  24. package/src/participant/ParticipantChannelBadges.test.tsx +59 -0
  25. package/src/participant/ParticipantChannelBadges.tsx +75 -0
  26. package/src/participant/ParticipantConversations.tsx +13 -6
  27. package/src/participant/ParticipantConversationsScreen.tsx +18 -7
  28. package/src/participant/ParticipantInbox.test.tsx +99 -2
  29. package/src/participant/ParticipantInbox.tsx +27 -46
  30. package/src/participant/ParticipantInboxRow.tsx +75 -0
  31. package/src/participant/ParticipantInboxSearchField.tsx +34 -0
  32. package/src/participant/ParticipantMessageBubble.test.tsx +2 -0
  33. package/src/participant/ParticipantMessageBubble.tsx +3 -3
  34. package/src/participant/ParticipantProtocolBadge.tsx +74 -0
  35. package/src/participant/ParticipantProtocolView.test.tsx +208 -0
  36. package/src/participant/ParticipantThread.test.tsx +19 -2
  37. package/src/participant/ParticipantThread.tsx +25 -15
  38. package/src/participant/index.ts +1 -0
  39. package/src/participant/participant.types.ts +9 -0
  40. package/src/participant/participantChannels.test.ts +42 -0
  41. package/src/participant/participantChannels.ts +33 -0
  42. package/src/participant/participantGrouping.test.ts +101 -3
  43. package/src/participant/participantGrouping.ts +20 -7
  44. package/src/participant/participantLabels.ts +29 -0
  45. package/src/participant/participantProtocol.test.ts +104 -0
  46. package/src/participant/participantProtocol.ts +52 -0
  47. package/src/participant/participantProtocolCopy.test.ts +45 -0
  48. package/src/participant/participantProtocolCopy.ts +32 -0
  49. package/src/styles.css +19 -1
  50. package/dist/chunk-WSFGNR5R.js +0 -55
@@ -1,17 +1,26 @@
1
1
  import {
2
2
  MessageText
3
- } from "../chunk-WSFGNR5R.js";
3
+ } from "../chunk-OVFCLRQQ.js";
4
4
  import {
5
5
  StatusTicks,
6
6
  channelCapabilityFor,
7
7
  formatFileSize,
8
8
  formatTimestamp,
9
9
  isSameDay
10
- } from "../chunk-RJMSM3YA.js";
10
+ } from "../chunk-O6457XHK.js";
11
11
  import "../chunk-CBYEHPX6.js";
12
12
 
13
13
  // src/participant/ParticipantConversationsScreen.tsx
14
- import { useMemo as useMemo4, useReducer as useReducer2, useRef as useRef7, useState as useState7 } from "react";
14
+ import { useMemo as useMemo4, useReducer as useReducer3, useRef as useRef7, useState as useState7 } from "react";
15
+
16
+ // src/participant/participantLoadView.ts
17
+ function resolveLoadView({ status, hasItems }) {
18
+ return {
19
+ isLoading: (status === "idle" || status === "loading") && !hasItems,
20
+ hasError: status === "error",
21
+ isEmpty: status === "ready" && !hasItems
22
+ };
23
+ }
15
24
 
16
25
  // src/participant/participantLabels.ts
17
26
  var DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS = {
@@ -52,44 +61,171 @@ var DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS = {
52
61
  notFound: "Conversation not found",
53
62
  loading: "Loading\u2026",
54
63
  loadError: "Could not load. Check your connection and try again.",
55
- loadMore: "Load more"
64
+ loadMore: "Load more",
65
+ searchLabel: "Search conversations",
66
+ searchPlaceholder: "Search by title or protocol",
67
+ noResults: "No conversations found",
68
+ noResultsInFilter: "No results in this filter \u2014 try All",
69
+ noResultsLoadedOnly: "Nothing in the loaded conversations \u2014 load more",
70
+ protocolPrefix: "Protocol",
71
+ copyProtocol: "Copy protocol",
72
+ protocolCopied: "Protocol copied",
73
+ channelsGroup: "Channels in this conversation",
74
+ channelApp: "App",
75
+ channelWhatsapp: "WhatsApp",
76
+ channelEmail: "Email",
77
+ channelPortal: "Portal",
78
+ channelWebchat: "Web chat"
56
79
  };
57
80
  function formatParticipantLabel(template, count) {
58
81
  return template.replace("{count}", String(count));
59
82
  }
60
83
 
61
- // src/participant/participantLoadView.ts
62
- function resolveLoadView({ status, hasItems }) {
63
- return {
64
- isLoading: (status === "idle" || status === "loading") && !hasItems,
65
- hasError: status === "error",
66
- isEmpty: status === "ready" && !hasItems
67
- };
84
+ // src/participant/ParticipantChannelBadges.tsx
85
+ import { Globe, Mail, MessageCircle, MessagesSquare, Smartphone } from "lucide-react";
86
+
87
+ // src/participant/participantChannels.ts
88
+ var PARTICIPANT_CHANNEL_ORDER = [
89
+ { channel: "app", iconName: "Smartphone", labelKey: "channelApp" },
90
+ { channel: "whatsapp", iconName: "MessageCircle", labelKey: "channelWhatsapp" },
91
+ { channel: "email", iconName: "Mail", labelKey: "channelEmail" },
92
+ { channel: "portal", iconName: "Globe", labelKey: "channelPortal" },
93
+ { channel: "webchat", iconName: "MessagesSquare", labelKey: "channelWebchat" }
94
+ ];
95
+ function resolveParticipantChannels(channels) {
96
+ if (channels === void 0 || channels.length === 0) return [];
97
+ const present = new Set(channels);
98
+ return PARTICIPANT_CHANNEL_ORDER.filter((descriptor) => present.has(descriptor.channel));
99
+ }
100
+ function resolveParticipantChannelLabel(descriptor, labels) {
101
+ return labels[descriptor.labelKey];
102
+ }
103
+
104
+ // src/participant/ParticipantChannelBadges.tsx
105
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
106
+ var ICONS = {
107
+ Smartphone,
108
+ MessageCircle,
109
+ Mail,
110
+ Globe,
111
+ MessagesSquare
112
+ };
113
+ function BadgeContent({ descriptor, labels, separator }) {
114
+ const Icon = ICONS[descriptor.iconName];
115
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
116
+ /* @__PURE__ */ jsx(Icon, { size: 14, "aria-hidden": true }),
117
+ /* @__PURE__ */ jsx("span", { className: "cv-p-sr-only", children: `${resolveParticipantChannelLabel(descriptor, labels)}${separator}` })
118
+ ] });
119
+ }
120
+ function ParticipantChannelBadges({ channels, labels, variant = "list" }) {
121
+ const descriptors = resolveParticipantChannels(channels);
122
+ if (descriptors.length === 0) return null;
123
+ if (variant === "inline") {
124
+ return /* @__PURE__ */ jsxs("span", { className: "cv-p-channels", children: [
125
+ /* @__PURE__ */ jsx("span", { className: "cv-p-sr-only", children: `${labels.channelsGroup}: ` }),
126
+ descriptors.map((descriptor, index) => /* @__PURE__ */ jsx("span", { className: `cv-p-channel cv-p-channel--${descriptor.channel}`, children: /* @__PURE__ */ jsx(
127
+ BadgeContent,
128
+ {
129
+ descriptor,
130
+ labels,
131
+ separator: index < descriptors.length - 1 ? ", " : ""
132
+ }
133
+ ) }, descriptor.channel))
134
+ ] });
135
+ }
136
+ return /* @__PURE__ */ jsx("ul", { className: "cv-p-channels", "aria-label": labels.channelsGroup, children: descriptors.map((descriptor) => /* @__PURE__ */ jsx("li", { className: `cv-p-channel cv-p-channel--${descriptor.channel}`, children: /* @__PURE__ */ jsx(BadgeContent, { descriptor, labels, separator: "" }) }, descriptor.channel)) });
137
+ }
138
+
139
+ // src/participant/ParticipantInboxRow.tsx
140
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
141
+ function formatRowTime(iso, locale) {
142
+ const date = new Date(iso);
143
+ if (isSameDay(date, /* @__PURE__ */ new Date())) return formatTimestamp(iso);
144
+ return date.toLocaleDateString(locale, { day: "2-digit", month: "2-digit" });
145
+ }
146
+ function RowIcon({ props, kind }) {
147
+ const custom = props.renderSubjectIcon?.(props.conversation);
148
+ if (custom !== null && custom !== void 0 && custom !== false && custom !== "") {
149
+ return /* @__PURE__ */ jsx2("span", { className: "cv-p-row__icon cv-p-inbox__icon", "aria-hidden": "true", children: custom });
150
+ }
151
+ return /* @__PURE__ */ jsx2("span", { className: "cv-p-row__icon", "aria-hidden": "true", children: props.group?.icon ?? kind.slice(0, 2) });
152
+ }
153
+ function ParticipantInboxRow(props) {
154
+ const { conversation, group, labels, locale, onSelect } = props;
155
+ const kind = group?.label ?? conversation.subjectType;
156
+ const className = conversation.awaitingParticipant ? "cv-p-row cv-p-row--awaiting" : "cv-p-row";
157
+ const { subjectType, subjectId } = conversation;
158
+ return /* @__PURE__ */ jsxs2("button", { type: "button", className, onClick: () => onSelect({ subjectType, subjectId }), children: [
159
+ /* @__PURE__ */ jsx2(RowIcon, { props, kind }),
160
+ /* @__PURE__ */ jsxs2("span", { className: "cv-p-row__body", children: [
161
+ /* @__PURE__ */ jsx2("span", { className: "cv-p-row__kind", children: kind }),
162
+ /* @__PURE__ */ jsx2("span", { className: "cv-p-row__title", children: conversation.subjectLabel }),
163
+ /* @__PURE__ */ jsxs2("span", { className: "cv-p-row__tags", children: [
164
+ conversation.protocol ? /* @__PURE__ */ jsxs2("span", { className: "cv-p-protocol", children: [
165
+ /* @__PURE__ */ jsxs2("span", { className: "cv-p-sr-only", children: [
166
+ labels.protocolPrefix,
167
+ " "
168
+ ] }),
169
+ conversation.protocol
170
+ ] }) : null,
171
+ /* @__PURE__ */ jsx2(ParticipantChannelBadges, { channels: conversation.channels, labels, variant: "inline" })
172
+ ] }),
173
+ conversation.lastMessagePreview ? /* @__PURE__ */ jsx2("span", { className: "cv-p-row__preview", children: conversation.lastMessagePreview }) : null
174
+ ] }),
175
+ /* @__PURE__ */ jsxs2("span", { className: "cv-p-row__meta", children: [
176
+ conversation.lastMessageAt ? /* @__PURE__ */ jsx2("span", { children: formatRowTime(conversation.lastMessageAt, locale) }) : null,
177
+ conversation.unreadCount > 0 ? /* @__PURE__ */ jsxs2("span", { className: "cv-p-row__unread", children: [
178
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: conversation.unreadCount }),
179
+ /* @__PURE__ */ jsx2("span", { className: "cv-p-sr-only", children: formatParticipantLabel(labels.unreadCount, conversation.unreadCount) })
180
+ ] }) : null
181
+ ] })
182
+ ] });
183
+ }
184
+
185
+ // src/participant/ParticipantInboxSearchField.tsx
186
+ import { useId } from "react";
187
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
188
+ function ParticipantInboxSearchField({ search, labels }) {
189
+ const inputId = useId();
190
+ return /* @__PURE__ */ jsxs3("div", { className: "cv-p-search", children: [
191
+ /* @__PURE__ */ jsx3("label", { className: "cv-p-sr-only", htmlFor: inputId, children: labels.searchLabel }),
192
+ /* @__PURE__ */ jsx3(
193
+ "input",
194
+ {
195
+ id: inputId,
196
+ type: "search",
197
+ className: "cv-p-search__input",
198
+ value: search.value,
199
+ placeholder: labels.searchPlaceholder,
200
+ autoComplete: "off",
201
+ onChange: (event) => search.onChange(event.target.value)
202
+ }
203
+ )
204
+ ] });
68
205
  }
69
206
 
70
207
  // src/participant/ParticipantLoadState.tsx
71
- import { jsx, jsxs } from "react/jsx-runtime";
208
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
72
209
  function ParticipantLoadError({ labels, onRetry }) {
73
- return /* @__PURE__ */ jsxs("div", { className: "cv-p-error", role: "alert", children: [
74
- /* @__PURE__ */ jsx("p", { className: "cv-p-error__message", children: labels.loadError }),
75
- /* @__PURE__ */ jsx("button", { type: "button", className: "cv-p-button", onClick: onRetry, children: labels.retry })
210
+ return /* @__PURE__ */ jsxs4("div", { className: "cv-p-error", role: "alert", children: [
211
+ /* @__PURE__ */ jsx4("p", { className: "cv-p-error__message", children: labels.loadError }),
212
+ /* @__PURE__ */ jsx4("button", { type: "button", className: "cv-p-button", onClick: onRetry, children: labels.retry })
76
213
  ] });
77
214
  }
78
215
  function ParticipantLoading({ labels }) {
79
- return /* @__PURE__ */ jsxs("div", { className: "cv-p-loading", children: [
80
- /* @__PURE__ */ jsx("span", { className: "cv-p-skeleton", "aria-hidden": "true" }),
81
- /* @__PURE__ */ jsx("span", { className: "cv-p-skeleton", "aria-hidden": "true" }),
82
- /* @__PURE__ */ jsx("span", { className: "cv-p-sr-only", children: labels.loading })
216
+ return /* @__PURE__ */ jsxs4("div", { className: "cv-p-loading", children: [
217
+ /* @__PURE__ */ jsx4("span", { className: "cv-p-skeleton", "aria-hidden": "true" }),
218
+ /* @__PURE__ */ jsx4("span", { className: "cv-p-skeleton", "aria-hidden": "true" }),
219
+ /* @__PURE__ */ jsx4("span", { className: "cv-p-sr-only", children: labels.loading })
83
220
  ] });
84
221
  }
85
222
 
86
223
  // src/participant/ParticipantInbox.tsx
87
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
224
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
88
225
  var ALL_FILTER = "all";
89
- function formatRowTime(iso, locale) {
90
- const date = new Date(iso);
91
- if (isSameDay(date, /* @__PURE__ */ new Date())) return formatTimestamp(iso);
92
- return date.toLocaleDateString(locale, { day: "2-digit", month: "2-digit" });
226
+ function resolveNoResultsLabel({ view, hasMore, labels }) {
227
+ if (view.hasMatchesOutsideFilter) return labels.noResultsInFilter;
228
+ return hasMore ? labels.noResultsLoadedOnly : labels.noResults;
93
229
  }
94
230
  function sectionTitle(section, props) {
95
231
  if (section.key === "awaiting") return props.labels.sectionAwaiting;
@@ -98,7 +234,7 @@ function sectionTitle(section, props) {
98
234
  return props.subjectGroups.find((group) => group.subjectType === section.key)?.label ?? section.key;
99
235
  }
100
236
  function Filters({ filters, active, labels, onChange }) {
101
- return /* @__PURE__ */ jsx2("div", { className: "cv-p-filters", role: "group", "aria-label": labels.filtersGroup, children: filters.map((filter) => /* @__PURE__ */ jsxs2(
237
+ return /* @__PURE__ */ jsx5("div", { className: "cv-p-filters", role: "group", "aria-label": labels.filtersGroup, children: filters.map((filter) => /* @__PURE__ */ jsxs5(
102
238
  "button",
103
239
  {
104
240
  type: "button",
@@ -107,79 +243,68 @@ function Filters({ filters, active, labels, onChange }) {
107
243
  onClick: () => onChange(filter.subjectType),
108
244
  children: [
109
245
  filter.subjectType === ALL_FILTER ? labels.filterAll : filter.label,
110
- filter.unreadCount > 0 ? /* @__PURE__ */ jsx2("b", { className: "cv-p-chip__count", children: filter.unreadCount }) : null
246
+ filter.unreadCount > 0 ? /* @__PURE__ */ jsx5("b", { className: "cv-p-chip__count", children: filter.unreadCount }) : null
111
247
  ]
112
248
  },
113
249
  filter.subjectType
114
250
  )) });
115
251
  }
116
- function Row({ conversation, group, labels, locale, onSelect }) {
117
- const kind = group?.label ?? conversation.subjectType;
118
- const className = conversation.awaitingParticipant ? "cv-p-row cv-p-row--awaiting" : "cv-p-row";
119
- const { subjectType, subjectId } = conversation;
120
- return /* @__PURE__ */ jsxs2("button", { type: "button", className, onClick: () => onSelect({ subjectType, subjectId }), children: [
121
- /* @__PURE__ */ jsx2("span", { className: "cv-p-row__icon", "aria-hidden": "true", children: group?.icon ?? kind.slice(0, 2) }),
122
- /* @__PURE__ */ jsxs2("span", { className: "cv-p-row__body", children: [
123
- /* @__PURE__ */ jsx2("span", { className: "cv-p-row__kind", children: kind }),
124
- /* @__PURE__ */ jsx2("span", { className: "cv-p-row__title", children: conversation.subjectLabel }),
125
- conversation.lastMessagePreview ? /* @__PURE__ */ jsx2("span", { className: "cv-p-row__preview", children: conversation.lastMessagePreview }) : null
126
- ] }),
127
- /* @__PURE__ */ jsxs2("span", { className: "cv-p-row__meta", children: [
128
- conversation.lastMessageAt ? /* @__PURE__ */ jsx2("span", { children: formatRowTime(conversation.lastMessageAt, locale) }) : null,
129
- conversation.unreadCount > 0 ? /* @__PURE__ */ jsxs2("span", { className: "cv-p-row__unread", children: [
130
- /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: conversation.unreadCount }),
131
- /* @__PURE__ */ jsx2("span", { className: "cv-p-sr-only", children: formatParticipantLabel(labels.unreadCount, conversation.unreadCount) })
132
- ] }) : null
133
- ] })
134
- ] });
135
- }
136
252
  function SectionHeading({ title, count }) {
137
- return /* @__PURE__ */ jsxs2(Fragment, { children: [
138
- /* @__PURE__ */ jsx2("span", { className: "cv-p-section__title", children: title }),
139
- /* @__PURE__ */ jsx2("span", { className: "cv-p-section__count", children: count })
253
+ return /* @__PURE__ */ jsxs5(Fragment2, { children: [
254
+ /* @__PURE__ */ jsx5("span", { className: "cv-p-section__title", children: title }),
255
+ /* @__PURE__ */ jsx5("span", { className: "cv-p-section__count", children: count })
140
256
  ] });
141
257
  }
142
- function Section({ section, props }) {
143
- const rows = section.conversations.map((conversation) => /* @__PURE__ */ jsx2(
144
- Row,
258
+ function Section({
259
+ section,
260
+ props
261
+ }) {
262
+ const rows = section.conversations.map((conversation) => /* @__PURE__ */ jsx5(
263
+ ParticipantInboxRow,
145
264
  {
146
265
  conversation,
147
266
  group: props.subjectGroups.find((group) => group.subjectType === conversation.subjectType),
148
267
  labels: props.labels,
149
268
  locale: props.locale,
150
- onSelect: props.onSelect
269
+ onSelect: props.onSelect,
270
+ renderSubjectIcon: props.renderSubjectIcon
151
271
  },
152
272
  `${conversation.subjectType}:${conversation.subjectId}`
153
273
  ));
154
- const heading = /* @__PURE__ */ jsx2(SectionHeading, { title: sectionTitle(section, props), count: section.conversations.length });
274
+ const heading = /* @__PURE__ */ jsx5(SectionHeading, { title: sectionTitle(section, props), count: section.conversations.length });
155
275
  if (section.key === "closed") {
156
- return /* @__PURE__ */ jsxs2("details", { className: "cv-p-section cv-p-section--closed", children: [
157
- /* @__PURE__ */ jsx2("summary", { className: "cv-p-section__heading", children: heading }),
276
+ return /* @__PURE__ */ jsxs5("details", { className: "cv-p-section cv-p-section--closed", children: [
277
+ /* @__PURE__ */ jsx5("summary", { className: "cv-p-section__heading", children: heading }),
158
278
  rows
159
279
  ] });
160
280
  }
161
281
  const modifier = section.key === "awaiting" ? " cv-p-section--awaiting" : "";
162
- return /* @__PURE__ */ jsxs2("section", { className: `cv-p-section${modifier}`, children: [
163
- /* @__PURE__ */ jsx2("h3", { className: "cv-p-section__heading", children: heading }),
282
+ return /* @__PURE__ */ jsxs5("section", { className: `cv-p-section${modifier}`, children: [
283
+ /* @__PURE__ */ jsx5("h3", { className: "cv-p-section__heading", children: heading }),
164
284
  rows
165
285
  ] });
166
286
  }
167
287
  function ParticipantInbox(props) {
168
288
  const { view, labels, filter, onFilterChange } = props;
169
- const loadView = resolveLoadView({ status: props.status, hasItems: view.sections.length > 0 });
170
- return /* @__PURE__ */ jsxs2("div", { className: "cv-p cv-p-inbox", "aria-busy": loadView.isLoading, children: [
171
- /* @__PURE__ */ jsx2("h2", { className: "cv-p-inbox__title", children: labels.inboxTitle }),
172
- view.showFilters ? /* @__PURE__ */ jsx2(Filters, { filters: view.filters, active: filter, labels, onChange: onFilterChange }) : null,
173
- loadView.isLoading ? /* @__PURE__ */ jsx2(ParticipantLoading, { labels }) : null,
174
- loadView.hasError ? /* @__PURE__ */ jsx2(ParticipantLoadError, { labels, onRetry: props.refresh }) : null,
175
- loadView.isEmpty ? /* @__PURE__ */ jsx2("p", { className: "cv-p-empty", children: labels.emptyInbox }) : null,
176
- view.sections.map((section) => /* @__PURE__ */ jsx2(Section, { section, props }, section.key)),
177
- props.hasMore ? /* @__PURE__ */ jsx2("button", { type: "button", className: "cv-p-button cv-p-inbox__more", onClick: props.loadMore, children: labels.loadMore }) : null
289
+ const isSearching = (props.search?.value.trim() ?? "") !== "";
290
+ const loadView = resolveLoadView({ status: props.status, hasItems: view.sections.length > 0 || isSearching });
291
+ const hasNoResults = isSearching && view.sections.length === 0 && props.status === "ready";
292
+ const noResultsLabel = resolveNoResultsLabel(props);
293
+ return /* @__PURE__ */ jsxs5("div", { className: "cv-p cv-p-inbox", "aria-busy": loadView.isLoading, children: [
294
+ /* @__PURE__ */ jsx5("h2", { className: "cv-p-inbox__title", children: labels.inboxTitle }),
295
+ view.showFilters ? /* @__PURE__ */ jsx5(Filters, { filters: view.filters, active: view.activeFilter, labels, onChange: onFilterChange }) : null,
296
+ props.search?.isVisible ? /* @__PURE__ */ jsx5(ParticipantInboxSearchField, { search: props.search, labels }) : null,
297
+ loadView.isLoading ? /* @__PURE__ */ jsx5(ParticipantLoading, { labels }) : null,
298
+ loadView.hasError ? /* @__PURE__ */ jsx5(ParticipantLoadError, { labels, onRetry: props.refresh }) : null,
299
+ loadView.isEmpty ? /* @__PURE__ */ jsx5("p", { className: "cv-p-empty", children: labels.emptyInbox }) : null,
300
+ hasNoResults ? /* @__PURE__ */ jsx5("p", { className: "cv-p-empty", children: noResultsLabel }) : null,
301
+ view.sections.map((section) => /* @__PURE__ */ jsx5(Section, { section, props }, section.key)),
302
+ props.hasMore ? /* @__PURE__ */ jsx5("button", { type: "button", className: "cv-p-button cv-p-inbox__more", onClick: props.loadMore, children: labels.loadMore }) : null
178
303
  ] });
179
304
  }
180
305
 
181
306
  // src/participant/ParticipantThreadScreen.tsx
182
- import { useEffect as useEffect7, useMemo as useMemo3, useState as useState6 } from "react";
307
+ import { useEffect as useEffect8, useMemo as useMemo3, useState as useState6 } from "react";
183
308
 
184
309
  // src/participant/ParticipantComposer.tsx
185
310
  import { useRef, useState } from "react";
@@ -217,18 +342,18 @@ function applyQuickReply(currentText, replyText) {
217
342
  }
218
343
 
219
344
  // src/participant/ParticipantComposer.tsx
220
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
345
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
221
346
  function QuickReplyStrip({ quickReplies, labels, onPick }) {
222
- return /* @__PURE__ */ jsx3("div", { className: "cv-p-quick", role: "group", "aria-label": labels.quickRepliesGroup, children: quickReplies.map((quickReply) => /* @__PURE__ */ jsx3("button", { type: "button", className: "cv-p-chip", onClick: () => onPick(quickReply.body), children: quickReply.title }, quickReply.id)) });
347
+ return /* @__PURE__ */ jsx6("div", { className: "cv-p-quick", role: "group", "aria-label": labels.quickRepliesGroup, children: quickReplies.map((quickReply) => /* @__PURE__ */ jsx6("button", { type: "button", className: "cv-p-chip", onClick: () => onPick(quickReply.body), children: quickReply.title }, quickReply.id)) });
223
348
  }
224
349
  function FileList({ files, labels, onRemove }) {
225
350
  if (files.length === 0) return null;
226
- return /* @__PURE__ */ jsx3("ul", { className: "cv-p-files", "aria-label": labels.attachmentsList, children: files.map((file, index) => /* @__PURE__ */ jsxs3("li", { className: "cv-p-files__item", children: [
227
- /* @__PURE__ */ jsx3("span", { className: "cv-p-files__name", children: file.name }),
228
- /* @__PURE__ */ jsx3("span", { className: "cv-p-files__size", children: formatFileSize(file.size) }),
229
- /* @__PURE__ */ jsxs3("button", { type: "button", className: "cv-p-files__remove", "aria-label": `${labels.removeAttachment}: ${file.name}`, onClick: () => onRemove(file), children: [
230
- /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\xD7" }),
231
- /* @__PURE__ */ jsx3("span", { className: "cv-p-sr-only", children: labels.removeAttachment })
351
+ return /* @__PURE__ */ jsx6("ul", { className: "cv-p-files", "aria-label": labels.attachmentsList, children: files.map((file, index) => /* @__PURE__ */ jsxs6("li", { className: "cv-p-files__item", children: [
352
+ /* @__PURE__ */ jsx6("span", { className: "cv-p-files__name", children: file.name }),
353
+ /* @__PURE__ */ jsx6("span", { className: "cv-p-files__size", children: formatFileSize(file.size) }),
354
+ /* @__PURE__ */ jsxs6("button", { type: "button", className: "cv-p-files__remove", "aria-label": `${labels.removeAttachment}: ${file.name}`, onClick: () => onRemove(file), children: [
355
+ /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\xD7" }),
356
+ /* @__PURE__ */ jsx6("span", { className: "cv-p-sr-only", children: labels.removeAttachment })
232
357
  ] })
233
358
  ] }, `${file.name}-${file.size}-${index}`)) });
234
359
  }
@@ -237,8 +362,8 @@ function rejectionText(rejection, labels) {
237
362
  }
238
363
  function AttachControl({ labels, disabled, acceptedTypes, onChosen }) {
239
364
  const fileInputRef = useRef(null);
240
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
241
- /* @__PURE__ */ jsx3(
365
+ return /* @__PURE__ */ jsxs6(Fragment3, { children: [
366
+ /* @__PURE__ */ jsx6(
242
367
  "input",
243
368
  {
244
369
  ref: fileInputRef,
@@ -250,9 +375,9 @@ function AttachControl({ labels, disabled, acceptedTypes, onChosen }) {
250
375
  onChange: onChosen
251
376
  }
252
377
  ),
253
- /* @__PURE__ */ jsxs3("button", { type: "button", className: "cv-p-button", disabled, onClick: () => fileInputRef.current?.click(), children: [
254
- /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\uFF0B" }),
255
- /* @__PURE__ */ jsx3("span", { className: "cv-p-sr-only", children: labels.attach })
378
+ /* @__PURE__ */ jsxs6("button", { type: "button", className: "cv-p-button", disabled, onClick: () => fileInputRef.current?.click(), children: [
379
+ /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\uFF0B" }),
380
+ /* @__PURE__ */ jsx6("span", { className: "cv-p-sr-only", children: labels.attach })
256
381
  ] })
257
382
  ] });
258
383
  }
@@ -281,13 +406,13 @@ function ParticipantComposer(props) {
281
406
  event.preventDefault();
282
407
  if (canSend) onSend();
283
408
  }
284
- return /* @__PURE__ */ jsxs3("form", { className: "cv-p-composer", onSubmit: handleSubmit, children: [
285
- props.quickReplies && props.quickReplies.length > 0 ? /* @__PURE__ */ jsx3(QuickReplyStrip, { quickReplies: props.quickReplies, labels, onPick: (body) => onChange(applyQuickReply(value, body)) }) : null,
286
- /* @__PURE__ */ jsx3(FileList, { files, labels, onRemove: handleRemoveFile }),
287
- rejection ? /* @__PURE__ */ jsx3("p", { className: "cv-p-composer__error", role: "alert", children: rejectionText(rejection, labels) }) : null,
288
- /* @__PURE__ */ jsxs3("div", { className: "cv-p-composer__row", children: [
289
- channelCapabilityFor(channel).attachments.accepted ? /* @__PURE__ */ jsx3(AttachControl, { labels, disabled, acceptedTypes: props.acceptedTypes, onChosen: handleFilesChosen }) : null,
290
- /* @__PURE__ */ jsx3(
409
+ return /* @__PURE__ */ jsxs6("form", { className: "cv-p-composer", onSubmit: handleSubmit, children: [
410
+ props.quickReplies && props.quickReplies.length > 0 ? /* @__PURE__ */ jsx6(QuickReplyStrip, { quickReplies: props.quickReplies, labels, onPick: (body) => onChange(applyQuickReply(value, body)) }) : null,
411
+ /* @__PURE__ */ jsx6(FileList, { files, labels, onRemove: handleRemoveFile }),
412
+ rejection ? /* @__PURE__ */ jsx6("p", { className: "cv-p-composer__error", role: "alert", children: rejectionText(rejection, labels) }) : null,
413
+ /* @__PURE__ */ jsxs6("div", { className: "cv-p-composer__row", children: [
414
+ channelCapabilityFor(channel).attachments.accepted ? /* @__PURE__ */ jsx6(AttachControl, { labels, disabled, acceptedTypes: props.acceptedTypes, onChosen: handleFilesChosen }) : null,
415
+ /* @__PURE__ */ jsx6(
291
416
  "textarea",
292
417
  {
293
418
  className: "cv-p-composer__input",
@@ -300,9 +425,9 @@ function ParticipantComposer(props) {
300
425
  onChange: (event) => onChange(event.target.value)
301
426
  }
302
427
  ),
303
- /* @__PURE__ */ jsxs3("button", { type: "submit", className: "cv-p-button cv-p-button--primary", disabled: !canSend, children: [
304
- /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u27A4" }),
305
- /* @__PURE__ */ jsx3("span", { className: "cv-p-sr-only", children: labels.send })
428
+ /* @__PURE__ */ jsxs6("button", { type: "submit", className: "cv-p-button cv-p-button--primary", disabled: !canSend, children: [
429
+ /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\u27A4" }),
430
+ /* @__PURE__ */ jsx6("span", { className: "cv-p-sr-only", children: labels.send })
306
431
  ] })
307
432
  ] })
308
433
  ] });
@@ -338,7 +463,7 @@ function isSafeAttachmentUrl(url) {
338
463
  }
339
464
 
340
465
  // src/participant/ParticipantAttachmentItem.tsx
341
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
466
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
342
467
  function useAttachmentUrl(attachment, resolveAttachmentUrl) {
343
468
  const [url, setUrl] = useState2(void 0);
344
469
  const disposition = attachment.kind === "document" ? "attachment" : "inline";
@@ -361,18 +486,18 @@ function useAttachmentUrl(attachment, resolveAttachmentUrl) {
361
486
  function ParticipantAttachmentItem({ attachment, resolveAttachmentUrl, labels }) {
362
487
  const url = useAttachmentUrl(attachment, resolveAttachmentUrl);
363
488
  if (attachment.kind === "image") {
364
- return /* @__PURE__ */ jsxs4("figure", { className: "cv-p-attachment cv-p-attachment--image", children: [
365
- url ? /* @__PURE__ */ jsx4("img", { className: "cv-p-attachment__image", src: url, alt: attachment.filename }) : null,
366
- /* @__PURE__ */ jsx4("figcaption", { className: "cv-p-attachment__name", children: attachment.filename })
489
+ return /* @__PURE__ */ jsxs7("figure", { className: "cv-p-attachment cv-p-attachment--image", children: [
490
+ url ? /* @__PURE__ */ jsx7("img", { className: "cv-p-attachment__image", src: url, alt: attachment.filename }) : null,
491
+ /* @__PURE__ */ jsx7("figcaption", { className: "cv-p-attachment__name", children: attachment.filename })
367
492
  ] });
368
493
  }
369
494
  if (attachment.kind === "audio") {
370
- return /* @__PURE__ */ jsxs4("div", { className: "cv-p-attachment cv-p-attachment--audio", children: [
371
- /* @__PURE__ */ jsx4("span", { className: "cv-p-attachment__name", children: attachment.filename }),
372
- /* @__PURE__ */ jsx4("audio", { className: "cv-p-attachment__audio", controls: true, preload: "none", src: url })
495
+ return /* @__PURE__ */ jsxs7("div", { className: "cv-p-attachment cv-p-attachment--audio", children: [
496
+ /* @__PURE__ */ jsx7("span", { className: "cv-p-attachment__name", children: attachment.filename }),
497
+ /* @__PURE__ */ jsx7("audio", { className: "cv-p-attachment__audio", controls: true, preload: "none", src: url })
373
498
  ] });
374
499
  }
375
- return /* @__PURE__ */ jsxs4(
500
+ return /* @__PURE__ */ jsxs7(
376
501
  "a",
377
502
  {
378
503
  className: "cv-p-attachment cv-p-attachment--document",
@@ -380,8 +505,8 @@ function ParticipantAttachmentItem({ attachment, resolveAttachmentUrl, labels })
380
505
  download: attachment.filename,
381
506
  "aria-label": `${labels.downloadAttachment}: ${attachment.filename}`,
382
507
  children: [
383
- /* @__PURE__ */ jsx4("span", { className: "cv-p-attachment__name", children: attachment.filename }),
384
- /* @__PURE__ */ jsx4("span", { className: "cv-p-attachment__size", children: formatFileSize(attachment.sizeBytes) })
508
+ /* @__PURE__ */ jsx7("span", { className: "cv-p-attachment__name", children: attachment.filename }),
509
+ /* @__PURE__ */ jsx7("span", { className: "cv-p-attachment__size", children: formatFileSize(attachment.sizeBytes) })
385
510
  ]
386
511
  }
387
512
  );
@@ -425,7 +550,7 @@ function resolveOwnMessageStatus(params) {
425
550
  }
426
551
 
427
552
  // src/participant/ParticipantMessageBubble.tsx
428
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
553
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
429
554
  function describeItem(item) {
430
555
  if (item.kind === "server") {
431
556
  const { message } = item;
@@ -463,22 +588,22 @@ function OwnStatus({ status, labels, onRetry }) {
463
588
  const ticksStatus = status === "sending" ? "queued" : status;
464
589
  const isVisibleText = status === "sending" || status === "queued" || status === "failed";
465
590
  if (status === "failed" && onRetry) {
466
- return /* @__PURE__ */ jsxs5("button", { type: "button", className: "cv-p-bubble__retry", onClick: onRetry, children: [
467
- /* @__PURE__ */ jsx5(StatusTicks, { status: "failed" }),
468
- /* @__PURE__ */ jsx5("span", { children: labels.statusFailed })
591
+ return /* @__PURE__ */ jsxs8("button", { type: "button", className: "cv-p-bubble__retry", onClick: onRetry, children: [
592
+ /* @__PURE__ */ jsx8(StatusTicks, { status: "failed", appearance: "stylesheet" }),
593
+ /* @__PURE__ */ jsx8("span", { children: labels.statusFailed })
469
594
  ] });
470
595
  }
471
596
  const text = status === "failed" ? labels.statusFailedShort : statusText(status, labels);
472
- return /* @__PURE__ */ jsxs5("span", { className: "cv-p-bubble__status", children: [
473
- /* @__PURE__ */ jsx5(StatusTicks, { status: ticksStatus }),
474
- /* @__PURE__ */ jsx5("span", { className: isVisibleText ? "cv-p-bubble__status-text" : "cv-p-sr-only", children: text })
597
+ return /* @__PURE__ */ jsxs8("span", { className: "cv-p-bubble__status", children: [
598
+ /* @__PURE__ */ jsx8(StatusTicks, { status: ticksStatus, appearance: "stylesheet" }),
599
+ /* @__PURE__ */ jsx8("span", { className: isVisibleText ? "cv-p-bubble__status-text" : "cv-p-sr-only", children: text })
475
600
  ] });
476
601
  }
477
602
  function FailedActions({ labels, onDiscard, onEdit }) {
478
603
  if (!onDiscard && !onEdit) return null;
479
- return /* @__PURE__ */ jsxs5("span", { className: "cv-p-bubble__actions", children: [
480
- onEdit ? /* @__PURE__ */ jsx5("button", { type: "button", className: "cv-p-bubble__action", onClick: onEdit, children: labels.edit }) : null,
481
- onDiscard ? /* @__PURE__ */ jsx5("button", { type: "button", className: "cv-p-bubble__action", onClick: onDiscard, children: labels.discard }) : null
604
+ return /* @__PURE__ */ jsxs8("span", { className: "cv-p-bubble__actions", children: [
605
+ onEdit ? /* @__PURE__ */ jsx8("button", { type: "button", className: "cv-p-bubble__action", onClick: onEdit, children: labels.edit }) : null,
606
+ onDiscard ? /* @__PURE__ */ jsx8("button", { type: "button", className: "cv-p-bubble__action", onClick: onDiscard, children: labels.discard }) : null
482
607
  ] });
483
608
  }
484
609
  function toTextPayload(text, createdAt, isMine) {
@@ -503,10 +628,10 @@ function ParticipantMessageBubble({
503
628
  const content = describeItem(item);
504
629
  const { isMine } = content;
505
630
  const ownStatus = isMine ? resolveOwnMessageStatus({ displayState: content.displayState, serverStatus: content.serverStatus, confirmsRead }) : void 0;
506
- return /* @__PURE__ */ jsxs5("div", { className: isMine ? "cv-p-bubble cv-p-bubble--mine" : "cv-p-bubble", children: [
507
- isMine ? /* @__PURE__ */ jsx5("span", { className: "cv-p-sr-only", children: labels.me }) : content.authorName ? /* @__PURE__ */ jsx5("span", { className: "cv-p-bubble__author", children: content.authorName }) : null,
508
- content.text ? /* @__PURE__ */ jsx5(MessageText, { message: toTextPayload(content.text, content.createdAt, isMine), copyOnClick: false }) : null,
509
- content.attachments.map((attachment) => /* @__PURE__ */ jsx5(
631
+ return /* @__PURE__ */ jsxs8("div", { className: isMine ? "cv-p-bubble cv-p-bubble--mine" : "cv-p-bubble", children: [
632
+ isMine ? /* @__PURE__ */ jsx8("span", { className: "cv-p-sr-only", children: labels.me }) : content.authorName ? /* @__PURE__ */ jsx8("span", { className: "cv-p-bubble__author", children: content.authorName }) : null,
633
+ content.text ? /* @__PURE__ */ jsx8(MessageText, { message: toTextPayload(content.text, content.createdAt, isMine), copyOnClick: false, appearance: "stylesheet" }) : null,
634
+ content.attachments.map((attachment) => /* @__PURE__ */ jsx8(
510
635
  ParticipantAttachmentItem,
511
636
  {
512
637
  attachment,
@@ -515,17 +640,90 @@ function ParticipantMessageBubble({
515
640
  },
516
641
  attachment.id
517
642
  )),
518
- content.pendingFilenames.map((filename, index) => /* @__PURE__ */ jsx5("span", { className: "cv-p-attachment cv-p-attachment--pending", children: filename }, `${filename}-${index}`)),
519
- /* @__PURE__ */ jsxs5("span", { className: "cv-p-bubble__meta", children: [
520
- /* @__PURE__ */ jsx5("time", { className: "cv-p-bubble__time", dateTime: content.createdAt, children: formatTimestamp(content.createdAt) }),
521
- ownStatus ? /* @__PURE__ */ jsx5(OwnStatus, { status: ownStatus, labels, onRetry }) : null
643
+ content.pendingFilenames.map((filename, index) => /* @__PURE__ */ jsx8("span", { className: "cv-p-attachment cv-p-attachment--pending", children: filename }, `${filename}-${index}`)),
644
+ /* @__PURE__ */ jsxs8("span", { className: "cv-p-bubble__meta", children: [
645
+ /* @__PURE__ */ jsx8("time", { className: "cv-p-bubble__time", dateTime: content.createdAt, children: formatTimestamp(content.createdAt) }),
646
+ ownStatus ? /* @__PURE__ */ jsx8(OwnStatus, { status: ownStatus, labels, onRetry }) : null
522
647
  ] }),
523
- ownStatus === "failed" ? /* @__PURE__ */ jsx5(FailedActions, { labels, onDiscard, onEdit }) : null
648
+ ownStatus === "failed" ? /* @__PURE__ */ jsx8(FailedActions, { labels, onDiscard, onEdit }) : null
524
649
  ] });
525
650
  }
526
651
 
652
+ // src/participant/ParticipantProtocolBadge.tsx
653
+ import { useEffect as useEffect2, useReducer } from "react";
654
+
655
+ // src/participant/participantProtocolCopy.ts
656
+ async function copyProtocolToClipboard(protocol, clipboard) {
657
+ if (clipboard === void 0) return false;
658
+ try {
659
+ await clipboard.writeText(protocol);
660
+ return true;
661
+ } catch {
662
+ return false;
663
+ }
664
+ }
665
+ var INITIAL_PROTOCOL_COPY_STATE = { copyCount: 0, isCopied: false };
666
+ function protocolCopyReducer(state, action) {
667
+ if (action.type === "copied") return { copyCount: state.copyCount + 1, isCopied: true };
668
+ return { ...state, isCopied: false };
669
+ }
670
+
671
+ // src/participant/ParticipantProtocolBadge.tsx
672
+ import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
673
+ var COPIED_ANNOUNCEMENT_MS = 3e3;
674
+ function ParticipantProtocolBadgeView({
675
+ protocol,
676
+ labels,
677
+ copyState,
678
+ onCopy
679
+ }) {
680
+ const { isCopied, copyCount } = copyState;
681
+ return /* @__PURE__ */ jsxs9(Fragment4, { children: [
682
+ /* @__PURE__ */ jsxs9("div", { className: "cv-p-protocol cv-p-protocol--header", children: [
683
+ /* @__PURE__ */ jsxs9("span", { className: "cv-p-protocol__code", children: [
684
+ /* @__PURE__ */ jsxs9("span", { className: "cv-p-sr-only", children: [
685
+ labels.protocolPrefix,
686
+ " "
687
+ ] }),
688
+ protocol
689
+ ] }),
690
+ /* @__PURE__ */ jsxs9("button", { type: "button", className: "cv-p-protocol__copy", onClick: onCopy, children: [
691
+ /* @__PURE__ */ jsx9("span", { "aria-hidden": "true", children: isCopied ? labels.protocolCopied : labels.copyProtocol }),
692
+ /* @__PURE__ */ jsxs9("span", { className: "cv-p-sr-only", children: [
693
+ labels.copyProtocol,
694
+ " ",
695
+ protocol
696
+ ] })
697
+ ] })
698
+ ] }),
699
+ /* @__PURE__ */ jsx9("div", { className: "cv-p-sr-only", role: "status", "aria-live": "polite", children: isCopied ? /* @__PURE__ */ jsx9("span", { children: labels.protocolCopied }, copyCount) : null })
700
+ ] });
701
+ }
702
+ function ParticipantProtocolBadge({ protocol, labels }) {
703
+ const [copyState, dispatch] = useReducer(protocolCopyReducer, INITIAL_PROTOCOL_COPY_STATE);
704
+ const { isCopied, copyCount } = copyState;
705
+ useEffect2(() => {
706
+ if (!isCopied) return void 0;
707
+ const timer = setTimeout(() => dispatch({ type: "expired" }), COPIED_ANNOUNCEMENT_MS);
708
+ return () => clearTimeout(timer);
709
+ }, [isCopied, copyCount]);
710
+ async function handleCopy() {
711
+ const clipboard = typeof navigator === "undefined" ? void 0 : navigator.clipboard;
712
+ if (await copyProtocolToClipboard(protocol, clipboard)) dispatch({ type: "copied" });
713
+ }
714
+ return /* @__PURE__ */ jsx9(
715
+ ParticipantProtocolBadgeView,
716
+ {
717
+ protocol,
718
+ labels,
719
+ copyState,
720
+ onCopy: () => void handleCopy()
721
+ }
722
+ );
723
+ }
724
+
527
725
  // src/participant/ParticipantThread.tsx
528
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
726
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
529
727
  function createdAtOf2(item) {
530
728
  return item.kind === "server" ? item.message.createdAt : item.pending.createdAt;
531
729
  }
@@ -539,21 +737,25 @@ function resolveActions(item, pendingActions) {
539
737
  function Header({ props }) {
540
738
  const { conversation, labels, onBack, onOpenSubject } = props;
541
739
  const { subjectType, subjectId } = conversation;
542
- return /* @__PURE__ */ jsxs6("header", { className: "cv-p-thread__header", children: [
543
- onBack ? /* @__PURE__ */ jsxs6("button", { type: "button", className: "cv-p-button cv-p-thread__back", onClick: onBack, children: [
544
- /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\u2039" }),
545
- /* @__PURE__ */ jsx6("span", { className: "cv-p-sr-only", children: labels.back })
740
+ return /* @__PURE__ */ jsxs10("header", { className: "cv-p-thread__header", children: [
741
+ onBack ? /* @__PURE__ */ jsxs10("button", { type: "button", className: "cv-p-button cv-p-thread__back", onClick: onBack, children: [
742
+ /* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: "\u2039" }),
743
+ /* @__PURE__ */ jsx10("span", { className: "cv-p-sr-only", children: labels.back })
546
744
  ] }) : null,
547
- /* @__PURE__ */ jsx6("h2", { className: "cv-p-thread__title", children: onOpenSubject ? /* @__PURE__ */ jsx6(
548
- "button",
549
- {
550
- type: "button",
551
- className: "cv-p-thread__title-button",
552
- "aria-label": `${labels.openSubject}: ${conversation.subjectLabel}`,
553
- onClick: () => onOpenSubject({ subjectType, subjectId }),
554
- children: conversation.subjectLabel
555
- }
556
- ) : conversation.subjectLabel })
745
+ /* @__PURE__ */ jsxs10("div", { className: "cv-p-thread__heading", children: [
746
+ /* @__PURE__ */ jsx10("h2", { className: "cv-p-thread__title", children: onOpenSubject ? /* @__PURE__ */ jsx10(
747
+ "button",
748
+ {
749
+ type: "button",
750
+ className: "cv-p-thread__title-button",
751
+ "aria-label": `${labels.openSubject}: ${conversation.subjectLabel}`,
752
+ onClick: () => onOpenSubject({ subjectType, subjectId }),
753
+ children: conversation.subjectLabel
754
+ }
755
+ ) : conversation.subjectLabel }),
756
+ conversation.protocol ? /* @__PURE__ */ jsx10(ParticipantProtocolBadge, { protocol: conversation.protocol, labels }) : null,
757
+ /* @__PURE__ */ jsx10(ParticipantChannelBadges, { channels: conversation.channels, labels })
758
+ ] })
557
759
  ] });
558
760
  }
559
761
  function Timeline({ props }) {
@@ -565,12 +767,12 @@ function Timeline({ props }) {
565
767
  const day = new Date(createdAtOf2(item));
566
768
  if (previousDay === void 0 || !isSameDay(previousDay, day)) {
567
769
  nodes.push(
568
- /* @__PURE__ */ jsx6("div", { className: "cv-p-day", role: "separator", children: day.toLocaleDateString(locale, { weekday: "short", day: "2-digit", month: "2-digit" }) }, `day:${keyOf(item)}`)
770
+ /* @__PURE__ */ jsx10("div", { className: "cv-p-day", role: "separator", children: day.toLocaleDateString(locale, { weekday: "short", day: "2-digit", month: "2-digit" }) }, `day:${keyOf(item)}`)
569
771
  );
570
772
  }
571
773
  previousDay = day;
572
774
  nodes.push(
573
- /* @__PURE__ */ jsx6(
775
+ /* @__PURE__ */ jsx10(
574
776
  ParticipantMessageBubble,
575
777
  {
576
778
  item,
@@ -583,14 +785,14 @@ function Timeline({ props }) {
583
785
  )
584
786
  );
585
787
  }
586
- return /* @__PURE__ */ jsx6("div", { className: "cv-p-thread__messages", children: nodes });
788
+ return /* @__PURE__ */ jsx10("div", { className: "cv-p-thread__messages", children: nodes });
587
789
  }
588
790
  function Footer({ props }) {
589
791
  const { conversation, labels, draft } = props;
590
792
  if (conversation.status === "closed") {
591
- return /* @__PURE__ */ jsx6("p", { className: "cv-p-thread__closed", children: labels.closedNotice });
793
+ return /* @__PURE__ */ jsx10("p", { className: "cv-p-thread__closed", children: labels.closedNotice });
592
794
  }
593
- return /* @__PURE__ */ jsx6(
795
+ return /* @__PURE__ */ jsx10(
594
796
  ParticipantComposer,
595
797
  {
596
798
  value: draft.value,
@@ -611,17 +813,17 @@ function ParticipantThread(props) {
611
813
  const { conversation, labels, hasMore, onLoadOlder, renderSubjectCard } = props;
612
814
  const subjectCard = renderSubjectCard?.(conversation);
613
815
  const loadView = resolveLoadView({ status: props.status, hasItems: props.items.length > 0 });
614
- return /* @__PURE__ */ jsxs6("div", { className: "cv-p cv-p-thread", "aria-busy": loadView.isLoading, children: [
615
- /* @__PURE__ */ jsx6(Header, { props }),
616
- subjectCard ? /* @__PURE__ */ jsx6("div", { className: "cv-p-thread__subject-card", children: subjectCard }) : null,
617
- /* @__PURE__ */ jsxs6("div", { className: "cv-p-thread__scroll", ref: props.scroll.ref, onScroll: props.scroll.onScroll, children: [
618
- loadView.isLoading ? /* @__PURE__ */ jsx6(ParticipantLoading, { labels }) : null,
619
- loadView.hasError ? /* @__PURE__ */ jsx6(ParticipantLoadError, { labels, onRetry: props.refresh }) : null,
620
- hasMore && onLoadOlder ? /* @__PURE__ */ jsx6("button", { type: "button", className: "cv-p-thread__older", onClick: onLoadOlder, children: labels.loadOlder }) : null,
621
- /* @__PURE__ */ jsx6(Timeline, { props })
816
+ return /* @__PURE__ */ jsxs10("div", { className: "cv-p cv-p-thread", "aria-busy": loadView.isLoading, children: [
817
+ /* @__PURE__ */ jsx10(Header, { props }),
818
+ subjectCard ? /* @__PURE__ */ jsx10("div", { className: "cv-p-thread__subject-card", children: subjectCard }) : null,
819
+ /* @__PURE__ */ jsxs10("div", { className: "cv-p-thread__scroll", ref: props.scroll.ref, onScroll: props.scroll.onScroll, children: [
820
+ loadView.isLoading ? /* @__PURE__ */ jsx10(ParticipantLoading, { labels }) : null,
821
+ loadView.hasError ? /* @__PURE__ */ jsx10(ParticipantLoadError, { labels, onRetry: props.refresh }) : null,
822
+ hasMore && onLoadOlder ? /* @__PURE__ */ jsx10("button", { type: "button", className: "cv-p-thread__older", onClick: onLoadOlder, children: labels.loadOlder }) : null,
823
+ /* @__PURE__ */ jsx10(Timeline, { props })
622
824
  ] }),
623
- /* @__PURE__ */ jsx6("div", { className: "cv-p-thread__live", role: "status", "aria-live": "polite", children: props.newMessagesCount > 0 ? labels.newMessages : "" }),
624
- /* @__PURE__ */ jsx6(Footer, { props })
825
+ /* @__PURE__ */ jsx10("div", { className: "cv-p-thread__live", role: "status", "aria-live": "polite", children: props.newMessagesCount > 0 ? labels.newMessages : "" }),
826
+ /* @__PURE__ */ jsx10(Footer, { props })
625
827
  ] });
626
828
  }
627
829
 
@@ -775,7 +977,7 @@ function participantSendStatesReducer(states, { subject, action }) {
775
977
  }
776
978
 
777
979
  // src/participant/useParticipantThread.ts
778
- import { useCallback as useCallback2, useEffect as useEffect5, useMemo, useReducer, useRef as useRef4 } from "react";
980
+ import { useCallback as useCallback2, useEffect as useEffect6, useMemo, useReducer as useReducer2, useRef as useRef4 } from "react";
779
981
 
780
982
  // src/participant/participantThreadState.ts
781
983
  var INITIAL_PARTICIPANT_THREAD_STATE = {
@@ -811,7 +1013,7 @@ function participantThreadReducer(state, action) {
811
1013
  }
812
1014
 
813
1015
  // src/participant/useParticipantMarkRead.ts
814
- import { useEffect as useEffect3 } from "react";
1016
+ import { useEffect as useEffect4 } from "react";
815
1017
 
816
1018
  // src/participant/shouldMarkRead.ts
817
1019
  function shouldMarkParticipantRead(params) {
@@ -823,12 +1025,12 @@ function shouldMarkParticipantRead(params) {
823
1025
  }
824
1026
 
825
1027
  // src/participant/useDocumentVisibility.ts
826
- import { useEffect as useEffect2, useState as useState4 } from "react";
1028
+ import { useEffect as useEffect3, useState as useState4 } from "react";
827
1029
  function useDocumentVisibility() {
828
1030
  const [visibilityState, setVisibilityState] = useState4(
829
1031
  () => typeof document === "undefined" ? "visible" : document.visibilityState
830
1032
  );
831
- useEffect2(() => {
1033
+ useEffect3(() => {
832
1034
  function handleVisibilityChange() {
833
1035
  setVisibilityState(document.visibilityState);
834
1036
  }
@@ -843,18 +1045,18 @@ function useDocumentVisibility() {
843
1045
  function useParticipantMarkRead(params) {
844
1046
  const { apiRef, subject, unreadCount, messageCount, onMarkedRead } = params;
845
1047
  const visibilityState = useDocumentVisibility();
846
- useEffect3(() => {
1048
+ useEffect4(() => {
847
1049
  if (!shouldMarkParticipantRead({ selected: subject, subject, visibilityState, unreadCount })) return;
848
1050
  void apiRef.current.markRead(subject).then(() => onMarkedRead?.(subject), () => void 0);
849
1051
  }, [apiRef, subject, visibilityState, unreadCount, messageCount, onMarkedRead]);
850
1052
  }
851
1053
 
852
1054
  // src/participant/useParticipantRevalidation.ts
853
- import { useEffect as useEffect4, useRef as useRef2 } from "react";
1055
+ import { useEffect as useEffect5, useRef as useRef2 } from "react";
854
1056
  function useParticipantRevalidation(api, onRevalidate) {
855
1057
  const handlerRef = useRef2(onRevalidate);
856
1058
  handlerRef.current = onRevalidate;
857
- useEffect4(() => {
1059
+ useEffect5(() => {
858
1060
  function handleFocus() {
859
1061
  handlerRef.current();
860
1062
  }
@@ -948,7 +1150,7 @@ function useParticipantThread(params) {
948
1150
  const { api, subject, channel, unreadCount = 0, onMarkedRead, sendEntries, dispatchSend, hostPending = [] } = params;
949
1151
  const { subjectType, subjectId } = subject;
950
1152
  const stableSubject = useMemo(() => ({ subjectType, subjectId }), [subjectType, subjectId]);
951
- const [state, dispatch] = useReducer(participantThreadReducer, INITIAL_PARTICIPANT_THREAD_STATE);
1153
+ const [state, dispatch] = useReducer2(participantThreadReducer, INITIAL_PARTICIPANT_THREAD_STATE);
952
1154
  const apiRef = useRef4(api);
953
1155
  apiRef.current = api;
954
1156
  const activeSubjectKey = useRef4("");
@@ -980,7 +1182,7 @@ function useParticipantThread(params) {
980
1182
  }, [stableSubject, subjectType, subjectId, oldestMessageId]);
981
1183
  const handleSentMessage = useCallback2((message) => dispatch({ type: "sendConfirmed", message }), []);
982
1184
  const sending = useParticipantSend({ apiRef, subject: stableSubject, entries: sendEntries, dispatchSend, onSentMessage: handleSentMessage });
983
- useEffect5(() => {
1185
+ useEffect6(() => {
984
1186
  activeSubjectKey.current = `${subjectType}:${subjectId}`;
985
1187
  dispatch({ type: "reset" });
986
1188
  void refresh();
@@ -988,7 +1190,7 @@ function useParticipantThread(params) {
988
1190
  useParticipantRevalidation(api, (event) => {
989
1191
  if (isForSubject(event, stableSubject)) void refresh();
990
1192
  });
991
- useEffect5(() => {
1193
+ useEffect6(() => {
992
1194
  if (sendEntries.length === 0) return;
993
1195
  dispatchSend({ type: "reflected", knownClientMessageIds: collectKnownClientMessageIds({ messages: state.messages, hostPending }) });
994
1196
  }, [sendEntries, state.messages, hostPending, dispatchSend]);
@@ -1029,7 +1231,7 @@ function useParticipantConversationView(params) {
1029
1231
  }
1030
1232
 
1031
1233
  // src/participant/useParticipantThreadScroll.ts
1032
- import { useEffect as useEffect6, useRef as useRef6 } from "react";
1234
+ import { useEffect as useEffect7, useRef as useRef6 } from "react";
1033
1235
 
1034
1236
  // src/participant/participantNewMessages.ts
1035
1237
  function collectServerMessageIds(items) {
@@ -1131,19 +1333,19 @@ function keyOf2(item) {
1131
1333
  function useParticipantThreadScroll(items) {
1132
1334
  const { scroll, isNearBottom } = useStickToBottom({ firstKey: keyOf2(items[0]), lastKey: keyOf2(items[items.length - 1]) });
1133
1335
  const seenIds = useRef6(/* @__PURE__ */ new Set());
1134
- useEffect6(() => {
1336
+ useEffect7(() => {
1135
1337
  if (isNearBottom) seenIds.current = collectServerMessageIds(items);
1136
1338
  }, [isNearBottom, items]);
1137
1339
  return { scroll, newMessagesCount: isNearBottom ? 0 : countNewIncomingMessages(seenIds.current, items) };
1138
1340
  }
1139
1341
 
1140
1342
  // src/participant/ParticipantThreadScreen.tsx
1141
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1343
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1142
1344
  function useOpenedConversation(api, subject, isNeeded) {
1143
1345
  const [opened, setOpened] = useState6({ status: "idle" });
1144
1346
  const { subjectType, subjectId } = subject;
1145
1347
  const canOpen = api.openConversation !== void 0;
1146
- useEffect7(() => {
1348
+ useEffect8(() => {
1147
1349
  if (!isNeeded || !canOpen) return;
1148
1350
  let isCurrent = true;
1149
1351
  setOpened({ status: "loading" });
@@ -1158,12 +1360,12 @@ function useOpenedConversation(api, subject, isNeeded) {
1158
1360
  return opened;
1159
1361
  }
1160
1362
  function NotFound({ labels, onBack }) {
1161
- return /* @__PURE__ */ jsxs7("div", { className: "cv-p cv-p-thread", children: [
1162
- /* @__PURE__ */ jsx7("header", { className: "cv-p-thread__header", children: onBack ? /* @__PURE__ */ jsxs7("button", { type: "button", className: "cv-p-button cv-p-thread__back", onClick: onBack, children: [
1163
- /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\u2039" }),
1164
- /* @__PURE__ */ jsx7("span", { className: "cv-p-sr-only", children: labels.back })
1363
+ return /* @__PURE__ */ jsxs11("div", { className: "cv-p cv-p-thread", children: [
1364
+ /* @__PURE__ */ jsx11("header", { className: "cv-p-thread__header", children: onBack ? /* @__PURE__ */ jsxs11("button", { type: "button", className: "cv-p-button cv-p-thread__back", onClick: onBack, children: [
1365
+ /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", children: "\u2039" }),
1366
+ /* @__PURE__ */ jsx11("span", { className: "cv-p-sr-only", children: labels.back })
1165
1367
  ] }) : null }),
1166
- /* @__PURE__ */ jsx7("p", { className: "cv-p-empty", children: labels.notFound })
1368
+ /* @__PURE__ */ jsx11("p", { className: "cv-p-empty", children: labels.notFound })
1167
1369
  ] });
1168
1370
  }
1169
1371
  function ParticipantThreadScreen(props) {
@@ -1173,11 +1375,11 @@ function ParticipantThreadScreen(props) {
1173
1375
  );
1174
1376
  const opened = useOpenedConversation(api, selected, listed === void 0);
1175
1377
  const conversation = listed ?? (opened.status === "found" ? opened.conversation : void 0);
1176
- if (conversation) return /* @__PURE__ */ jsx7(LoadedThread, { ...props, conversation });
1378
+ if (conversation) return /* @__PURE__ */ jsx11(LoadedThread, { ...props, conversation });
1177
1379
  const isResolving = opened.status === "loading" || api.openConversation !== void 0 && opened.status === "idle";
1178
1380
  const isListLoading = inbox.status === "idle" || inbox.status === "loading";
1179
- if (isResolving || api.openConversation === void 0 && isListLoading) return /* @__PURE__ */ jsx7("div", { className: "cv-p cv-p-thread", "aria-busy": "true" });
1180
- return /* @__PURE__ */ jsx7(NotFound, { labels, onBack: props.onBack });
1381
+ if (isResolving || api.openConversation === void 0 && isListLoading) return /* @__PURE__ */ jsx11("div", { className: "cv-p cv-p-thread", "aria-busy": "true" });
1382
+ return /* @__PURE__ */ jsx11(NotFound, { labels, onBack: props.onBack });
1181
1383
  }
1182
1384
  function LoadedThread(props) {
1183
1385
  const { api, selected, conversation, draftsRef, inbox } = props;
@@ -1199,7 +1401,7 @@ function LoadedThread(props) {
1199
1401
  restoreFromEntry(entry);
1200
1402
  dispatchSend({ type: "discarded", clientMessageId });
1201
1403
  }
1202
- return /* @__PURE__ */ jsx7(
1404
+ return /* @__PURE__ */ jsx11(
1203
1405
  ParticipantThread,
1204
1406
  {
1205
1407
  conversation,
@@ -1231,6 +1433,39 @@ function LoadedThread(props) {
1231
1433
  );
1232
1434
  }
1233
1435
 
1436
+ // src/participant/participantProtocol.ts
1437
+ var PROTOCOL_SEARCH_CONVERSATION_THRESHOLD = 8;
1438
+ function normalizeProtocolQuery(text) {
1439
+ return text.replace(/[-\s]/g, "").toUpperCase();
1440
+ }
1441
+ function matchesProtocolQuery(protocol, query) {
1442
+ const normalizedQuery = normalizeProtocolQuery(query);
1443
+ if (normalizedQuery === "") return true;
1444
+ if (protocol === void 0) return false;
1445
+ return normalizeProtocolQuery(protocol).includes(normalizedQuery);
1446
+ }
1447
+ function foldText(text) {
1448
+ return text.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase();
1449
+ }
1450
+ function matchesTitle(subjectLabel, query) {
1451
+ return foldText(subjectLabel).includes(foldText(query));
1452
+ }
1453
+ function filterConversationsBySearch(conversations, query) {
1454
+ const trimmedQuery = query.trim();
1455
+ if (trimmedQuery === "") return conversations;
1456
+ const hasProtocolTerm = normalizeProtocolQuery(trimmedQuery) !== "";
1457
+ return conversations.filter(
1458
+ (conversation) => matchesTitle(conversation.subjectLabel, trimmedQuery) || hasProtocolTerm && matchesProtocolQuery(conversation.protocol, trimmedQuery)
1459
+ );
1460
+ }
1461
+ function isInboxSearchVisible({ conversations, searchQuery }) {
1462
+ return searchQuery !== "" || shouldShowInboxSearch(conversations);
1463
+ }
1464
+ function shouldShowInboxSearch(conversations) {
1465
+ if (conversations.length > PROTOCOL_SEARCH_CONVERSATION_THRESHOLD) return true;
1466
+ return conversations.some((conversation) => conversation.protocol !== void 0);
1467
+ }
1468
+
1234
1469
  // src/participant/participantGrouping.ts
1235
1470
  var ALL_FILTER2 = "all";
1236
1471
  var SECTION_AWAITING = "awaiting";
@@ -1270,22 +1505,35 @@ function buildFilters(params) {
1270
1505
  };
1271
1506
  return { filters: [all, ...groupFilters], showFilters: groupFilters.length >= 2 };
1272
1507
  }
1508
+ function resolveActiveFilter(params) {
1509
+ const { filter, conversations } = params;
1510
+ if (filter === void 0 || filter === ALL_FILTER2) return ALL_FILTER2;
1511
+ return conversations.some((conversation) => conversation.subjectType === filter) ? filter : ALL_FILTER2;
1512
+ }
1273
1513
  function groupParticipantConversations(params) {
1274
- const { filter, subjectGroups } = params;
1275
- const isFiltered = filter !== void 0 && filter !== ALL_FILTER2;
1276
- const visible = isFiltered ? params.conversations.filter((conversation) => conversation.subjectType === filter) : params.conversations;
1514
+ const { subjectGroups } = params;
1515
+ const filter = resolveActiveFilter(params);
1516
+ const isFiltered = filter !== ALL_FILTER2;
1517
+ const searched = filterConversationsBySearch(params.conversations, params.searchQuery ?? "");
1518
+ const visible = isFiltered ? searched.filter((conversation) => conversation.subjectType === filter) : searched;
1277
1519
  const knownTypes = new Set(subjectGroups.map((group) => group.subjectType));
1278
1520
  const buckets = /* @__PURE__ */ new Map();
1279
1521
  for (const conversation of visible) {
1280
1522
  const key = resolveSectionKey(conversation, knownTypes);
1281
1523
  buckets.set(key, [...buckets.get(key) ?? [], conversation]);
1282
1524
  }
1283
- const orderedKeys = [SECTION_AWAITING, ...subjectGroups.map((group) => group.subjectType), SECTION_OTHER, SECTION_CLOSED];
1525
+ const orderedKeys = [
1526
+ SECTION_AWAITING,
1527
+ ...subjectGroups.map((group) => group.subjectType),
1528
+ SECTION_OTHER,
1529
+ SECTION_CLOSED
1530
+ ];
1284
1531
  const sections = orderedKeys.flatMap((key) => {
1285
1532
  const bucket = buckets.get(key);
1286
1533
  return bucket === void 0 ? [] : [buildSection(key, bucket)];
1287
1534
  });
1288
- return { sections, ...buildFilters(params) };
1535
+ const hasMatchesOutsideFilter = isFiltered && visible.length === 0 && searched.length > 0;
1536
+ return { sections, hasMatchesOutsideFilter, activeFilter: filter, ...buildFilters(params) };
1289
1537
  }
1290
1538
 
1291
1539
  // src/participant/participantTheme.ts
@@ -1306,23 +1554,27 @@ function buildParticipantThemeStyle(theme) {
1306
1554
  }
1307
1555
 
1308
1556
  // src/participant/ParticipantConversationsScreen.tsx
1309
- import { jsx as jsx8 } from "react/jsx-runtime";
1557
+ import { jsx as jsx12 } from "react/jsx-runtime";
1310
1558
  var ALL_FILTER3 = "all";
1311
1559
  function ParticipantConversationsScreen(props) {
1312
1560
  const { selected, inbox, subjectGroups, classNames } = props;
1313
1561
  const [filter, setFilter] = useState7(ALL_FILTER3);
1562
+ const [searchQuery, setSearchQuery] = useState7("");
1314
1563
  const draftsRef = useRef7(/* @__PURE__ */ new Map());
1315
- const [sendStates, dispatchSendStates] = useReducer2(participantSendStatesReducer, /* @__PURE__ */ new Map());
1316
- const labels = useMemo4(
1317
- () => ({ ...DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS, ...props.labels }),
1318
- [props.labels]
1319
- );
1564
+ const [sendStates, dispatchSendStates] = useReducer3(participantSendStatesReducer, /* @__PURE__ */ new Map());
1565
+ const labels = useMemo4(() => ({ ...DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS, ...props.labels }), [props.labels]);
1320
1566
  const view = useMemo4(
1321
- () => groupParticipantConversations({ conversations: inbox.conversations, subjectGroups, filter }),
1322
- [inbox.conversations, subjectGroups, filter]
1567
+ () => groupParticipantConversations({
1568
+ conversations: inbox.conversations,
1569
+ subjectGroups,
1570
+ filter,
1571
+ searchQuery
1572
+ }),
1573
+ [inbox.conversations, subjectGroups, filter, searchQuery]
1323
1574
  );
1575
+ const isSearchVisible = isInboxSearchVisible({ conversations: inbox.conversations, searchQuery });
1324
1576
  const rootClassName = ["cv-p-root", props.className, classNames?.root].filter(Boolean).join(" ");
1325
- return /* @__PURE__ */ jsx8("div", { className: rootClassName, style: buildParticipantThemeStyle(props.theme), children: selected === void 0 ? /* @__PURE__ */ jsx8("div", { className: ["cv-p-root__screen", classNames?.inbox].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx8(
1577
+ return /* @__PURE__ */ jsx12("div", { className: rootClassName, style: buildParticipantThemeStyle(props.theme), children: selected === void 0 ? /* @__PURE__ */ jsx12("div", { className: ["cv-p-root__screen", classNames?.inbox].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx12(
1326
1578
  ParticipantInbox,
1327
1579
  {
1328
1580
  view,
@@ -1335,9 +1587,11 @@ function ParticipantConversationsScreen(props) {
1335
1587
  refresh: () => void inbox.refresh(),
1336
1588
  hasMore: inbox.hasMore,
1337
1589
  loadMore: () => void inbox.loadMore(),
1338
- locale: props.locale
1590
+ locale: props.locale,
1591
+ renderSubjectIcon: props.renderSubjectIcon,
1592
+ search: { value: searchQuery, onChange: setSearchQuery, isVisible: isSearchVisible }
1339
1593
  }
1340
- ) }) : /* @__PURE__ */ jsx8("div", { className: ["cv-p-root__screen", classNames?.thread].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx8(
1594
+ ) }) : /* @__PURE__ */ jsx12("div", { className: ["cv-p-root__screen", classNames?.thread].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx12(
1341
1595
  ParticipantThreadScreen,
1342
1596
  {
1343
1597
  ...props,
@@ -1352,7 +1606,7 @@ function ParticipantConversationsScreen(props) {
1352
1606
  }
1353
1607
 
1354
1608
  // src/participant/useParticipantInbox.ts
1355
- import { useCallback as useCallback5, useEffect as useEffect8, useReducer as useReducer3 } from "react";
1609
+ import { useCallback as useCallback5, useEffect as useEffect9, useReducer as useReducer4 } from "react";
1356
1610
 
1357
1611
  // src/participant/participantInboxState.ts
1358
1612
  var INITIAL_PARTICIPANT_INBOX_STATE = { status: "idle", conversations: [] };
@@ -1402,7 +1656,7 @@ function describeError2(error) {
1402
1656
  return error instanceof Error ? error.message : "unknown error";
1403
1657
  }
1404
1658
  function useParticipantInbox(api) {
1405
- const [state, dispatch] = useReducer3(participantInboxReducer, INITIAL_PARTICIPANT_INBOX_STATE);
1659
+ const [state, dispatch] = useReducer4(participantInboxReducer, INITIAL_PARTICIPANT_INBOX_STATE);
1406
1660
  const refresh = useCallback5(async () => {
1407
1661
  dispatch({ type: "started" });
1408
1662
  try {
@@ -1425,7 +1679,7 @@ function useParticipantInbox(api) {
1425
1679
  const markSubjectRead = useCallback5((subject) => {
1426
1680
  dispatch({ type: "markedRead", subject });
1427
1681
  }, []);
1428
- useEffect8(() => {
1682
+ useEffect9(() => {
1429
1683
  void refresh();
1430
1684
  }, [refresh]);
1431
1685
  useParticipantRevalidation(api, () => {
@@ -1435,11 +1689,17 @@ function useParticipantInbox(api) {
1435
1689
  }
1436
1690
 
1437
1691
  // src/participant/ParticipantConversations.tsx
1438
- import { jsx as jsx9 } from "react/jsx-runtime";
1692
+ import { jsx as jsx13 } from "react/jsx-runtime";
1439
1693
  function ParticipantConversations(props) {
1440
1694
  const inbox = useParticipantInbox(props.api);
1441
1695
  const { status, conversations, hasMore, refresh, loadMore, markSubjectRead } = inbox;
1442
- return /* @__PURE__ */ jsx9(ParticipantConversationsScreen, { ...props, inbox: { status, conversations, hasMore, refresh, loadMore, markSubjectRead } });
1696
+ return /* @__PURE__ */ jsx13(
1697
+ ParticipantConversationsScreen,
1698
+ {
1699
+ ...props,
1700
+ inbox: { status, conversations, hasMore, refresh, loadMore, markSubjectRead }
1701
+ }
1702
+ );
1443
1703
  }
1444
1704
  export {
1445
1705
  DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS,