@echothink-ui/inbox 0.1.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 (52) hide show
  1. package/README.md +5 -0
  2. package/dist/components/AgentDraftReviewPanel.d.ts +18 -0
  3. package/dist/components/ApprovalToSendPanel.d.ts +11 -0
  4. package/dist/components/AttachmentList.d.ts +8 -0
  5. package/dist/components/AttachmentPreview.d.ts +7 -0
  6. package/dist/components/EmailAutomationRulePanel.d.ts +8 -0
  7. package/dist/components/InboxShell.d.ts +10 -0
  8. package/dist/components/LabelManager.d.ts +9 -0
  9. package/dist/components/MailboxFolderList.d.ts +8 -0
  10. package/dist/components/MessageComposer.d.ts +13 -0
  11. package/dist/components/MessageFilterBar.d.ts +13 -0
  12. package/dist/components/MessageList.d.ts +8 -0
  13. package/dist/components/MessagePreview.d.ts +9 -0
  14. package/dist/components/MessageSearch.d.ts +11 -0
  15. package/dist/components/MessageThread.d.ts +22 -0
  16. package/dist/components/PriorityInboxView.d.ts +14 -0
  17. package/dist/components/RecipientPicker.d.ts +10 -0
  18. package/dist/components/ThreadSummaryPanel.d.ts +9 -0
  19. package/dist/index.cjs +1699 -0
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/index.css +2155 -0
  22. package/dist/index.css.map +1 -0
  23. package/dist/index.d.ts +21 -0
  24. package/dist/index.js +1645 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/types.d.ts +75 -0
  27. package/dist/utils.d.ts +5 -0
  28. package/package.json +44 -0
  29. package/src/components/AgentDraftReviewPanel.tsx +128 -0
  30. package/src/components/ApprovalToSendPanel.tsx +118 -0
  31. package/src/components/AttachmentList.tsx +85 -0
  32. package/src/components/AttachmentPreview.tsx +207 -0
  33. package/src/components/EmailAutomationRulePanel.tsx +100 -0
  34. package/src/components/InboxShell.tsx +62 -0
  35. package/src/components/LabelManager.tsx +147 -0
  36. package/src/components/MailboxFolderList.tsx +66 -0
  37. package/src/components/MessageComposer.tsx +160 -0
  38. package/src/components/MessageFilterBar.test.tsx +34 -0
  39. package/src/components/MessageFilterBar.tsx +69 -0
  40. package/src/components/MessageList.tsx +101 -0
  41. package/src/components/MessagePreview.test.tsx +48 -0
  42. package/src/components/MessagePreview.tsx +84 -0
  43. package/src/components/MessageSearch.tsx +96 -0
  44. package/src/components/MessageThread.tsx +173 -0
  45. package/src/components/PriorityInboxView.tsx +74 -0
  46. package/src/components/RecipientPicker.tsx +181 -0
  47. package/src/components/ThreadSummaryPanel.tsx +107 -0
  48. package/src/index.test.tsx +276 -0
  49. package/src/index.tsx +60 -0
  50. package/src/styles.css +2523 -0
  51. package/src/types.ts +85 -0
  52. package/src/utils.ts +33 -0
package/dist/index.js ADDED
@@ -0,0 +1,1645 @@
1
+ // src/components/InboxShell.tsx
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function InboxShell({
4
+ folders,
5
+ list,
6
+ thread,
7
+ inspector,
8
+ toolbar,
9
+ className,
10
+ title,
11
+ description,
12
+ ...props
13
+ }) {
14
+ const hasInspector = Boolean(inspector);
15
+ return /* @__PURE__ */ jsxs(
16
+ "section",
17
+ {
18
+ ...props,
19
+ className: `eth-inbox-shell ${className ?? ""}`,
20
+ "data-eth-component": "InboxShell",
21
+ children: [
22
+ (title || description || toolbar) && /* @__PURE__ */ jsxs("header", { className: "eth-inbox-shell__header", children: [
23
+ /* @__PURE__ */ jsxs("div", { children: [
24
+ title ? /* @__PURE__ */ jsx("h2", { children: title }) : null,
25
+ description ? /* @__PURE__ */ jsx("p", { children: description }) : null
26
+ ] }),
27
+ toolbar ? /* @__PURE__ */ jsx("div", { className: "eth-inbox-shell__toolbar", children: toolbar }) : null
28
+ ] }),
29
+ /* @__PURE__ */ jsxs(
30
+ "div",
31
+ {
32
+ className: `eth-inbox-shell__layout ${hasInspector ? "eth-inbox-shell__layout--has-inspector" : ""}`,
33
+ children: [
34
+ /* @__PURE__ */ jsx("aside", { className: "eth-inbox-shell__folders", "aria-label": "Mailbox folders", children: folders }),
35
+ /* @__PURE__ */ jsx("aside", { className: "eth-inbox-shell__list", "aria-label": "Message list", children: list }),
36
+ /* @__PURE__ */ jsx("main", { className: "eth-inbox-shell__thread", "aria-label": "Selected conversation", children: thread }),
37
+ inspector ? /* @__PURE__ */ jsx("aside", { className: "eth-inbox-shell__inspector", "aria-label": "Conversation inspector", children: inspector }) : null
38
+ ]
39
+ }
40
+ )
41
+ ]
42
+ }
43
+ );
44
+ }
45
+
46
+ // src/components/MailboxFolderList.tsx
47
+ import { Badge } from "@echothink-ui/core";
48
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
49
+ function MailboxFolderList({
50
+ folders = [],
51
+ activeFolderId,
52
+ onSelect,
53
+ className,
54
+ "aria-label": ariaLabel = "Mailbox folders",
55
+ ...props
56
+ }) {
57
+ return /* @__PURE__ */ jsx2(
58
+ "nav",
59
+ {
60
+ ...props,
61
+ className: ["eth-inbox-folders", className].filter(Boolean).join(" "),
62
+ "data-eth-component": "MailboxFolderList",
63
+ "aria-label": ariaLabel,
64
+ children: /* @__PURE__ */ jsx2("ul", { className: "eth-inbox-folders__list", children: folders.map((folder) => {
65
+ const isActive = activeFolderId === folder.id;
66
+ return /* @__PURE__ */ jsx2("li", { children: /* @__PURE__ */ jsxs2(
67
+ "button",
68
+ {
69
+ type: "button",
70
+ className: [
71
+ "eth-inbox-folders__item",
72
+ isActive ? "eth-inbox-folders__item--active" : "",
73
+ folder.smart ? "eth-inbox-folders__item--smart" : ""
74
+ ].filter(Boolean).join(" "),
75
+ "aria-current": isActive ? "page" : void 0,
76
+ onClick: () => onSelect?.(folder.id),
77
+ title: folder.label,
78
+ children: [
79
+ folder.icon ? /* @__PURE__ */ jsx2("span", { className: "eth-inbox-folders__icon", "aria-hidden": "true", children: folder.icon }) : null,
80
+ /* @__PURE__ */ jsx2("span", { className: "eth-inbox-folders__label", children: folder.label }),
81
+ typeof folder.count === "number" ? /* @__PURE__ */ jsx2(Badge, { className: "eth-inbox-folders__count", "aria-label": `${folder.count} items`, children: folder.count }) : null
82
+ ]
83
+ }
84
+ ) }, folder.id);
85
+ }) })
86
+ }
87
+ );
88
+ }
89
+
90
+ // src/components/MessageList.tsx
91
+ import { Badge as Badge2, StatusDot, Tag, statusLabel } from "@echothink-ui/core";
92
+
93
+ // src/utils.ts
94
+ function formatDateTime(value) {
95
+ const date = new Date(value);
96
+ if (Number.isNaN(date.getTime())) return value;
97
+ return new Intl.DateTimeFormat(void 0, {
98
+ month: "short",
99
+ day: "numeric",
100
+ hour: "numeric",
101
+ minute: "2-digit"
102
+ }).format(date);
103
+ }
104
+ function formatBytes(size) {
105
+ if (size < 1024) return `${size} B`;
106
+ if (size < 1024 * 1024) return `${Math.round(size / 1024)} KB`;
107
+ return `${(size / (1024 * 1024)).toFixed(1)} MB`;
108
+ }
109
+ function listToInput(value) {
110
+ return value?.join(", ") ?? "";
111
+ }
112
+ function inputToList(value) {
113
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
114
+ }
115
+ function prioritySeverity(priority) {
116
+ if (priority === "high") return "danger";
117
+ if (priority === "low") return "neutral";
118
+ return "info";
119
+ }
120
+
121
+ // src/components/MessageList.tsx
122
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
123
+ function MessageList({
124
+ threads = [],
125
+ selectedThreadId,
126
+ onSelect,
127
+ className,
128
+ ...props
129
+ }) {
130
+ const hasThreads = threads.length > 0;
131
+ return /* @__PURE__ */ jsx3(
132
+ "div",
133
+ {
134
+ ...props,
135
+ className: `eth-inbox-message-list ${className ?? ""}`,
136
+ role: "listbox",
137
+ "aria-label": "Message threads",
138
+ "data-eth-component": "MessageList",
139
+ children: hasThreads ? threads.map((thread, index) => {
140
+ const receivedAtLabel = formatDateTime(thread.receivedAt);
141
+ const selected = selectedThreadId === thread.id;
142
+ const hasMeta = Boolean(thread.priority || thread.labels?.length || thread.status);
143
+ return /* @__PURE__ */ jsxs3(
144
+ "button",
145
+ {
146
+ type: "button",
147
+ role: "option",
148
+ "aria-label": [
149
+ thread.unread ? "Unread" : "Read",
150
+ `From ${thread.from}`,
151
+ thread.subject,
152
+ `Received ${receivedAtLabel}`,
153
+ thread.priority ? `${thread.priority} priority` : null,
154
+ thread.status ? statusLabel(thread.status) : null
155
+ ].filter(Boolean).join(", "),
156
+ "aria-posinset": index + 1,
157
+ "aria-selected": selected,
158
+ "aria-setsize": threads.length,
159
+ className: `eth-inbox-message-list__row ${thread.unread ? "eth-inbox-message-list__row--unread" : ""}`,
160
+ onClick: () => onSelect?.(thread.id),
161
+ children: [
162
+ /* @__PURE__ */ jsx3("span", { className: "eth-inbox-message-list__selection", "aria-hidden": "true" }),
163
+ /* @__PURE__ */ jsxs3("span", { className: "eth-inbox-message-list__content", children: [
164
+ /* @__PURE__ */ jsxs3("span", { className: "eth-inbox-message-list__header", children: [
165
+ /* @__PURE__ */ jsxs3("span", { className: "eth-inbox-message-list__from-group", children: [
166
+ /* @__PURE__ */ jsx3("span", { className: "eth-inbox-message-list__unread", "aria-hidden": "true" }),
167
+ /* @__PURE__ */ jsx3("span", { className: "eth-inbox-message-list__from", children: thread.from })
168
+ ] }),
169
+ /* @__PURE__ */ jsx3("time", { className: "eth-inbox-message-list__date", dateTime: thread.receivedAt, children: receivedAtLabel })
170
+ ] }),
171
+ /* @__PURE__ */ jsx3("strong", { className: "eth-inbox-message-list__subject", children: thread.subject }),
172
+ /* @__PURE__ */ jsx3("span", { className: "eth-inbox-message-list__preview", children: thread.preview }),
173
+ hasMeta ? /* @__PURE__ */ jsxs3("span", { className: "eth-inbox-message-list__meta", children: [
174
+ thread.priority ? /* @__PURE__ */ jsx3(Badge2, { severity: prioritySeverity(thread.priority), children: thread.priority }) : null,
175
+ thread.labels?.map((label) => /* @__PURE__ */ jsx3(Tag, { children: label }, label)),
176
+ thread.status ? /* @__PURE__ */ jsx3(StatusDot, { status: thread.status, label: statusLabel(thread.status) }) : null
177
+ ] }) : null
178
+ ] })
179
+ ]
180
+ },
181
+ thread.id
182
+ );
183
+ }) : /* @__PURE__ */ jsx3(
184
+ "div",
185
+ {
186
+ className: "eth-inbox-message-list__empty",
187
+ role: "status",
188
+ "aria-label": "No message threads",
189
+ children: "No message threads"
190
+ }
191
+ )
192
+ }
193
+ );
194
+ }
195
+
196
+ // src/components/MessageThread.tsx
197
+ import * as React2 from "react";
198
+ import { Badge as Badge3, Button, StatusDot as StatusDot2 } from "@echothink-ui/core";
199
+
200
+ // src/components/MessagePreview.tsx
201
+ import * as React from "react";
202
+
203
+ // src/components/AttachmentList.tsx
204
+ import { IconButton } from "@echothink-ui/core";
205
+ import { DocumentIcon, DownloadIcon, ViewIcon } from "@echothink-ui/icons";
206
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
207
+ function AttachmentList({
208
+ attachments = [],
209
+ onPreview,
210
+ onDownload,
211
+ className,
212
+ role,
213
+ "aria-label": ariaLabel,
214
+ ...props
215
+ }) {
216
+ if (!attachments.length) return null;
217
+ return /* @__PURE__ */ jsx4(
218
+ "div",
219
+ {
220
+ ...props,
221
+ className: ["eth-inbox-attachments", className].filter(Boolean).join(" "),
222
+ "data-eth-component": "AttachmentList",
223
+ role: role ?? "list",
224
+ "aria-label": ariaLabel ?? "Message attachments",
225
+ children: attachments.map((attachment) => {
226
+ const typeLabel = attachmentTypeLabel(attachment);
227
+ const hasActions = Boolean(onPreview || onDownload);
228
+ return /* @__PURE__ */ jsxs4("div", { className: "eth-inbox-attachments__tile", role: "listitem", children: [
229
+ /* @__PURE__ */ jsx4("span", { className: "eth-inbox-attachments__icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(DocumentIcon, { size: 18 }) }),
230
+ /* @__PURE__ */ jsxs4("div", { className: "eth-inbox-attachments__content", children: [
231
+ /* @__PURE__ */ jsx4("strong", { title: attachment.name, children: attachment.name }),
232
+ /* @__PURE__ */ jsxs4("span", { className: "eth-inbox-attachments__meta", children: [
233
+ /* @__PURE__ */ jsx4("span", { className: "eth-inbox-attachments__type", children: typeLabel }),
234
+ /* @__PURE__ */ jsx4("span", { children: attachment.mimeType }),
235
+ /* @__PURE__ */ jsx4("span", { children: formatBytes(attachment.size) })
236
+ ] })
237
+ ] }),
238
+ hasActions ? /* @__PURE__ */ jsxs4(
239
+ "div",
240
+ {
241
+ className: "eth-inbox-attachments__actions",
242
+ "aria-label": `Actions for ${attachment.name}`,
243
+ children: [
244
+ onPreview ? /* @__PURE__ */ jsx4(
245
+ IconButton,
246
+ {
247
+ intent: "ghost",
248
+ density: "compact",
249
+ label: `Preview ${attachment.name}`,
250
+ icon: /* @__PURE__ */ jsx4(ViewIcon, { size: 16 }),
251
+ onClick: () => onPreview(attachment)
252
+ }
253
+ ) : null,
254
+ onDownload ? /* @__PURE__ */ jsx4(
255
+ IconButton,
256
+ {
257
+ intent: "ghost",
258
+ density: "compact",
259
+ label: `Download ${attachment.name}`,
260
+ icon: /* @__PURE__ */ jsx4(DownloadIcon, { size: 16 }),
261
+ onClick: () => onDownload(attachment)
262
+ }
263
+ ) : null
264
+ ]
265
+ }
266
+ ) : null
267
+ ] }, attachment.id);
268
+ })
269
+ }
270
+ );
271
+ }
272
+ function attachmentTypeLabel(attachment) {
273
+ const extension = attachment.name.split(".").pop();
274
+ if (extension && extension !== attachment.name) return extension.slice(0, 4).toUpperCase();
275
+ const subtype = attachment.mimeType.split("/").pop();
276
+ return subtype ? subtype.slice(0, 4).toUpperCase() : "FILE";
277
+ }
278
+
279
+ // src/components/MessagePreview.tsx
280
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
281
+ function MessagePreview({
282
+ message,
283
+ showSubject = true,
284
+ onPreviewAttachment,
285
+ onDownloadAttachment,
286
+ className,
287
+ "aria-label": ariaLabel,
288
+ "aria-labelledby": ariaLabelledBy,
289
+ ...props
290
+ }) {
291
+ const subjectId = React.useId();
292
+ const attachmentsHeadingId = React.useId();
293
+ const visibleSubject = showSubject ? message.subject : void 0;
294
+ const labelledBy = ariaLabel ? ariaLabelledBy : ariaLabelledBy ?? (visibleSubject ? subjectId : void 0);
295
+ const computedAriaLabel = ariaLabel ?? (labelledBy ? void 0 : "Message preview");
296
+ const hasAttachments = Boolean(message.attachments?.length);
297
+ return /* @__PURE__ */ jsxs5(
298
+ "article",
299
+ {
300
+ ...props,
301
+ className: ["eth-inbox-message-preview", className].filter(Boolean).join(" "),
302
+ "data-eth-component": "MessagePreview",
303
+ "aria-label": computedAriaLabel,
304
+ "aria-labelledby": labelledBy,
305
+ children: [
306
+ /* @__PURE__ */ jsxs5("header", { className: "eth-inbox-message-preview__header", children: [
307
+ /* @__PURE__ */ jsxs5("div", { className: "eth-inbox-message-preview__heading", children: [
308
+ visibleSubject ? /* @__PURE__ */ jsx5("h3", { id: subjectId, children: visibleSubject }) : null,
309
+ /* @__PURE__ */ jsxs5("dl", { className: "eth-inbox-message-preview__recipients", "aria-label": "Message routing", children: [
310
+ /* @__PURE__ */ jsxs5("div", { children: [
311
+ /* @__PURE__ */ jsx5("dt", { children: "From" }),
312
+ /* @__PURE__ */ jsx5("dd", { children: message.from })
313
+ ] }),
314
+ /* @__PURE__ */ jsxs5("div", { children: [
315
+ /* @__PURE__ */ jsx5("dt", { children: "To" }),
316
+ /* @__PURE__ */ jsx5("dd", { children: formatRecipients(message.to) })
317
+ ] }),
318
+ message.cc?.length ? /* @__PURE__ */ jsxs5("div", { children: [
319
+ /* @__PURE__ */ jsx5("dt", { children: "Cc" }),
320
+ /* @__PURE__ */ jsx5("dd", { children: formatRecipients(message.cc) })
321
+ ] }) : null
322
+ ] })
323
+ ] }),
324
+ /* @__PURE__ */ jsx5("time", { dateTime: message.date, children: formatDateTime(message.date) })
325
+ ] }),
326
+ /* @__PURE__ */ jsx5("div", { className: "eth-inbox-message-preview__body", children: /* @__PURE__ */ jsx5("p", { children: message.body }) }),
327
+ hasAttachments ? /* @__PURE__ */ jsxs5(
328
+ "section",
329
+ {
330
+ className: "eth-inbox-message-preview__attachments",
331
+ "aria-labelledby": attachmentsHeadingId,
332
+ children: [
333
+ /* @__PURE__ */ jsx5("h4", { id: attachmentsHeadingId, children: "Attachments" }),
334
+ /* @__PURE__ */ jsx5(
335
+ AttachmentList,
336
+ {
337
+ attachments: message.attachments,
338
+ onPreview: onPreviewAttachment,
339
+ onDownload: onDownloadAttachment
340
+ }
341
+ )
342
+ ]
343
+ }
344
+ ) : null
345
+ ]
346
+ }
347
+ );
348
+ }
349
+ function formatRecipients(recipients) {
350
+ return recipients.length ? recipients.join(", ") : "No recipients";
351
+ }
352
+
353
+ // src/components/MessageThread.tsx
354
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
355
+ function MessageThread({
356
+ thread,
357
+ summaryRef,
358
+ status,
359
+ statusLabel: statusLabel2,
360
+ actions = [],
361
+ onPreviewAttachment,
362
+ onDownloadAttachment,
363
+ className,
364
+ ...props
365
+ }) {
366
+ const messages = React2.useMemo(
367
+ () => [...thread?.messages ?? []].sort(
368
+ (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
369
+ ),
370
+ [thread?.messages]
371
+ );
372
+ const older = messages.slice(0, Math.max(0, messages.length - 3));
373
+ const recent = messages.slice(Math.max(0, messages.length - 3));
374
+ const participantCount = countParticipants(messages);
375
+ const attachmentCount = messages.reduce(
376
+ (count, message) => count + (message.attachments?.length ?? 0),
377
+ 0
378
+ );
379
+ const latestMessage = messages.at(-1);
380
+ const messageLabel = formatCount(messages.length, "message");
381
+ const participantLabel = formatCount(participantCount, "participant");
382
+ const attachmentLabel = formatCount(attachmentCount, "attachment");
383
+ return /* @__PURE__ */ jsxs6(
384
+ "article",
385
+ {
386
+ ...props,
387
+ className: `eth-inbox-thread ${className ?? ""}`,
388
+ "data-eth-component": "MessageThread",
389
+ children: [
390
+ /* @__PURE__ */ jsxs6("header", { className: "eth-inbox-thread__header", children: [
391
+ /* @__PURE__ */ jsxs6("div", { className: "eth-inbox-thread__heading", children: [
392
+ /* @__PURE__ */ jsx6("span", { className: "eth-inbox-thread__eyebrow", children: "Conversation thread" }),
393
+ /* @__PURE__ */ jsx6("h2", { children: thread?.subject ?? "Thread" }),
394
+ /* @__PURE__ */ jsxs6("ul", { className: "eth-inbox-thread__meta", "aria-label": "Thread metadata", children: [
395
+ /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(Badge3, { severity: "neutral", children: messageLabel }) }),
396
+ /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(Badge3, { severity: "neutral", children: participantLabel }) }),
397
+ attachmentCount ? /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(Badge3, { severity: "info", children: attachmentLabel }) }) : null,
398
+ status ? /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(StatusDot2, { status, label: statusLabel2 ?? statusToLabel(status) }) }) : null,
399
+ latestMessage ? /* @__PURE__ */ jsxs6("li", { className: "eth-inbox-thread__updated", children: [
400
+ "Last activity",
401
+ " ",
402
+ /* @__PURE__ */ jsx6("time", { dateTime: latestMessage.date, children: formatDateTime(latestMessage.date) })
403
+ ] }) : null
404
+ ] })
405
+ ] }),
406
+ actions.length ? /* @__PURE__ */ jsx6("div", { className: "eth-inbox-thread__actions", role: "group", "aria-label": "Thread actions", children: actions.map((action) => /* @__PURE__ */ jsx6(
407
+ Button,
408
+ {
409
+ intent: action.intent ?? "secondary",
410
+ density: action.density ?? "compact",
411
+ disabled: action.disabled,
412
+ icon: action.icon,
413
+ onClick: action.onSelect,
414
+ children: action.label
415
+ },
416
+ action.id
417
+ )) }) : null
418
+ ] }),
419
+ summaryRef ? /* @__PURE__ */ jsxs6("aside", { className: "eth-inbox-thread__summary", "aria-label": "Thread summary", children: [
420
+ /* @__PURE__ */ jsx6("span", { className: "eth-inbox-thread__summary-label", children: "Thread summary" }),
421
+ /* @__PURE__ */ jsx6("div", { className: "eth-inbox-thread__summary-body", children: summaryRef })
422
+ ] }) : null,
423
+ !messages.length ? /* @__PURE__ */ jsxs6("div", { className: "eth-inbox-thread__empty", role: "status", children: [
424
+ /* @__PURE__ */ jsx6("strong", { children: "No messages in this thread" }),
425
+ /* @__PURE__ */ jsx6("span", { children: "Replies, summaries, and attachment activity will appear here." })
426
+ ] }) : null,
427
+ older.length ? /* @__PURE__ */ jsxs6("details", { className: "eth-inbox-thread__older", children: [
428
+ /* @__PURE__ */ jsx6("summary", { children: formatCount(older.length, "older message") }),
429
+ older.map((message) => /* @__PURE__ */ jsx6(
430
+ MessagePreview,
431
+ {
432
+ message,
433
+ showSubject: false,
434
+ onPreviewAttachment,
435
+ onDownloadAttachment
436
+ },
437
+ message.id
438
+ ))
439
+ ] }) : null,
440
+ /* @__PURE__ */ jsx6("div", { className: "eth-inbox-thread__messages", children: recent.map((message) => /* @__PURE__ */ jsx6(
441
+ MessagePreview,
442
+ {
443
+ message,
444
+ showSubject: false,
445
+ onPreviewAttachment,
446
+ onDownloadAttachment
447
+ },
448
+ message.id
449
+ )) })
450
+ ]
451
+ }
452
+ );
453
+ }
454
+ function countParticipants(messages) {
455
+ const participants = /* @__PURE__ */ new Set();
456
+ messages.forEach((message) => {
457
+ participants.add(message.from);
458
+ message.to.forEach((recipient) => participants.add(recipient));
459
+ message.cc?.forEach((recipient) => participants.add(recipient));
460
+ message.bcc?.forEach((recipient) => participants.add(recipient));
461
+ });
462
+ return participants.size;
463
+ }
464
+ function formatCount(value, singular) {
465
+ return `${value} ${value === 1 ? singular : `${singular}s`}`;
466
+ }
467
+ function statusToLabel(status) {
468
+ return status.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
469
+ }
470
+
471
+ // src/components/MessageComposer.tsx
472
+ import * as React3 from "react";
473
+ import { Button as Button2, FormField, Textarea, TextInput } from "@echothink-ui/core";
474
+ import { DocumentIcon as DocumentIcon2, MessageIcon } from "@echothink-ui/icons";
475
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
476
+ function MessageComposer({
477
+ draft = {},
478
+ onChange,
479
+ onSend,
480
+ onDiscard,
481
+ onAttach,
482
+ recipients,
483
+ attachments,
484
+ statusText,
485
+ className,
486
+ ...props
487
+ }) {
488
+ const [localDraft, setLocalDraft] = React3.useState(draft);
489
+ React3.useEffect(() => setLocalDraft(draft), [draft]);
490
+ const update = (next) => {
491
+ setLocalDraft(next);
492
+ onChange?.(next);
493
+ };
494
+ const draftAttachments = localDraft.attachments ?? [];
495
+ const hasAttachmentsRegion = Boolean(attachments || draftAttachments.length || onAttach);
496
+ return /* @__PURE__ */ jsxs7(
497
+ "form",
498
+ {
499
+ ...props,
500
+ className: ["eth-inbox-composer", className].filter(Boolean).join(" "),
501
+ "data-eth-component": "MessageComposer",
502
+ onSubmit: (event) => {
503
+ event.preventDefault();
504
+ onSend?.(localDraft);
505
+ },
506
+ children: [
507
+ /* @__PURE__ */ jsxs7("div", { className: "eth-inbox-composer__fields", children: [
508
+ recipients ?? /* @__PURE__ */ jsxs7("div", { className: "eth-inbox-composer__address-fields", role: "group", "aria-label": "Recipients", children: [
509
+ /* @__PURE__ */ jsx7(
510
+ FormField,
511
+ {
512
+ className: "eth-inbox-composer__field eth-inbox-composer__field--address",
513
+ label: "To",
514
+ children: /* @__PURE__ */ jsx7(
515
+ TextInput,
516
+ {
517
+ density: "compact",
518
+ placeholder: "name@company.com",
519
+ value: listToInput(localDraft.to),
520
+ onChange: (event) => update({ ...localDraft, to: inputToList(event.currentTarget.value) })
521
+ }
522
+ )
523
+ }
524
+ ),
525
+ /* @__PURE__ */ jsx7(
526
+ FormField,
527
+ {
528
+ className: "eth-inbox-composer__field eth-inbox-composer__field--address",
529
+ label: "CC",
530
+ children: /* @__PURE__ */ jsx7(
531
+ TextInput,
532
+ {
533
+ density: "compact",
534
+ placeholder: "Optional",
535
+ value: listToInput(localDraft.cc),
536
+ onChange: (event) => update({ ...localDraft, cc: inputToList(event.currentTarget.value) })
537
+ }
538
+ )
539
+ }
540
+ ),
541
+ /* @__PURE__ */ jsx7(
542
+ FormField,
543
+ {
544
+ className: "eth-inbox-composer__field eth-inbox-composer__field--address",
545
+ label: "BCC",
546
+ children: /* @__PURE__ */ jsx7(
547
+ TextInput,
548
+ {
549
+ density: "compact",
550
+ placeholder: "Optional",
551
+ value: listToInput(localDraft.bcc),
552
+ onChange: (event) => update({ ...localDraft, bcc: inputToList(event.currentTarget.value) })
553
+ }
554
+ )
555
+ }
556
+ )
557
+ ] }),
558
+ /* @__PURE__ */ jsx7(
559
+ FormField,
560
+ {
561
+ className: "eth-inbox-composer__field eth-inbox-composer__field--subject",
562
+ label: "Subject",
563
+ children: /* @__PURE__ */ jsx7(
564
+ TextInput,
565
+ {
566
+ density: "compact",
567
+ value: localDraft.subject ?? "",
568
+ onChange: (event) => update({ ...localDraft, subject: event.currentTarget.value })
569
+ }
570
+ )
571
+ }
572
+ ),
573
+ /* @__PURE__ */ jsx7(
574
+ FormField,
575
+ {
576
+ className: "eth-inbox-composer__field eth-inbox-composer__field--body",
577
+ label: "Body",
578
+ children: /* @__PURE__ */ jsx7(
579
+ Textarea,
580
+ {
581
+ value: localDraft.body ?? "",
582
+ rows: 10,
583
+ onChange: (event) => update({ ...localDraft, body: event.currentTarget.value })
584
+ }
585
+ )
586
+ }
587
+ )
588
+ ] }),
589
+ hasAttachmentsRegion ? /* @__PURE__ */ jsxs7("section", { className: "eth-inbox-composer__attachments", "aria-label": "Draft attachments", children: [
590
+ /* @__PURE__ */ jsxs7("div", { className: "eth-inbox-composer__attachments-header", children: [
591
+ /* @__PURE__ */ jsx7("span", { children: "Attachments" }),
592
+ onAttach ? /* @__PURE__ */ jsx7(
593
+ Button2,
594
+ {
595
+ type: "button",
596
+ intent: "tertiary",
597
+ density: "compact",
598
+ icon: /* @__PURE__ */ jsx7(DocumentIcon2, { size: 16 }),
599
+ onClick: onAttach,
600
+ children: "Attach file"
601
+ }
602
+ ) : null
603
+ ] }),
604
+ attachments ?? (draftAttachments.length ? /* @__PURE__ */ jsx7(AttachmentList, { attachments: draftAttachments }) : /* @__PURE__ */ jsx7("p", { className: "eth-inbox-composer__empty-attachments", children: "No attachments added" }))
605
+ ] }) : null,
606
+ /* @__PURE__ */ jsxs7("div", { className: "eth-inbox-composer__footer", children: [
607
+ statusText ? /* @__PURE__ */ jsx7("p", { className: "eth-inbox-composer__status", children: statusText }) : null,
608
+ /* @__PURE__ */ jsxs7("div", { className: "eth-inbox-composer__actions", children: [
609
+ /* @__PURE__ */ jsx7(Button2, { type: "submit", icon: /* @__PURE__ */ jsx7(MessageIcon, { size: 16 }), children: "Send" }),
610
+ /* @__PURE__ */ jsx7(Button2, { type: "button", intent: "tertiary", onClick: onDiscard, children: "Discard" })
611
+ ] })
612
+ ] })
613
+ ]
614
+ }
615
+ );
616
+ }
617
+
618
+ // src/components/AttachmentPreview.tsx
619
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
620
+ function AttachmentPreview({
621
+ attachment,
622
+ children,
623
+ className,
624
+ ...props
625
+ }) {
626
+ const kind = getPreviewKind(attachment);
627
+ const previewSource = attachment?.previewUrl ?? attachment?.src;
628
+ const hasCustomPreview = children !== void 0 && children !== null;
629
+ const label = attachment ? `Attachment preview for ${attachment.name}` : "Attachment preview";
630
+ return /* @__PURE__ */ jsxs8(
631
+ "section",
632
+ {
633
+ ...props,
634
+ "aria-label": props["aria-label"] ?? label,
635
+ className: `eth-inbox-attachment-preview ${className ?? ""}`,
636
+ "data-eth-component": "AttachmentPreview",
637
+ children: [
638
+ attachment ? /* @__PURE__ */ jsxs8("header", { className: "eth-inbox-attachment-preview__header", children: [
639
+ /* @__PURE__ */ jsxs8("div", { className: "eth-inbox-attachment-preview__file", children: [
640
+ /* @__PURE__ */ jsx8(
641
+ "span",
642
+ {
643
+ className: "eth-inbox-attachment-preview__glyph",
644
+ "data-kind": kind,
645
+ "aria-hidden": "true",
646
+ children: kindToken(kind)
647
+ }
648
+ ),
649
+ /* @__PURE__ */ jsxs8("div", { className: "eth-inbox-attachment-preview__summary", children: [
650
+ /* @__PURE__ */ jsx8("strong", { title: attachment.name, children: attachment.name }),
651
+ /* @__PURE__ */ jsxs8("span", { children: [
652
+ attachment.mimeType,
653
+ " - ",
654
+ formatBytes(attachment.size)
655
+ ] })
656
+ ] })
657
+ ] }),
658
+ /* @__PURE__ */ jsx8("span", { className: "eth-inbox-attachment-preview__state", children: previewStateLabel(kind) })
659
+ ] }) : null,
660
+ /* @__PURE__ */ jsx8(
661
+ "div",
662
+ {
663
+ className: `eth-inbox-attachment-preview__body eth-inbox-attachment-preview__body--${kind}`,
664
+ children: hasCustomPreview ? children : renderDefaultPreview(attachment, kind, previewSource)
665
+ }
666
+ )
667
+ ]
668
+ }
669
+ );
670
+ }
671
+ function getPreviewKind(attachment) {
672
+ if (!attachment) return "empty";
673
+ const mimeType = attachment.mimeType.toLowerCase();
674
+ const name = attachment.name.toLowerCase();
675
+ if (mimeType === "application/pdf" || name.endsWith(".pdf")) return "pdf";
676
+ if (mimeType.startsWith("image/")) return "image";
677
+ if (mimeType.includes("spreadsheet") || mimeType.includes("csv") || name.endsWith(".csv") || name.endsWith(".xls") || name.endsWith(".xlsx")) {
678
+ return "spreadsheet";
679
+ }
680
+ if (mimeType.startsWith("text/") || ["application/json", "application/xml", "application/yaml"].includes(mimeType) || name.endsWith(".md")) {
681
+ return "text";
682
+ }
683
+ if (mimeType.includes("zip") || mimeType.includes("compressed") || name.endsWith(".zip") || name.endsWith(".gz")) {
684
+ return "archive";
685
+ }
686
+ return "file";
687
+ }
688
+ function kindToken(kind) {
689
+ if (kind === "pdf") return "PDF";
690
+ if (kind === "image") return "IMG";
691
+ if (kind === "text") return "TXT";
692
+ if (kind === "spreadsheet") return "CSV";
693
+ if (kind === "archive") return "ZIP";
694
+ return "FILE";
695
+ }
696
+ function previewStateLabel(kind) {
697
+ if (kind === "archive" || kind === "file") return "Preview unavailable";
698
+ return "Inline preview";
699
+ }
700
+ function renderDefaultPreview(attachment, kind, previewSource) {
701
+ if (!attachment) {
702
+ return /* @__PURE__ */ jsxs8("div", { className: "eth-inbox-attachment-preview__empty", children: [
703
+ /* @__PURE__ */ jsx8("strong", { children: "No attachment selected" }),
704
+ /* @__PURE__ */ jsx8("span", { children: "PDF, image, text, and spreadsheet files can be previewed inline." })
705
+ ] });
706
+ }
707
+ if (kind === "image") {
708
+ return previewSource ? /* @__PURE__ */ jsx8(
709
+ "img",
710
+ {
711
+ className: "eth-inbox-attachment-preview__image",
712
+ src: previewSource,
713
+ alt: `${attachment.name} preview`
714
+ }
715
+ ) : /* @__PURE__ */ jsxs8(
716
+ "div",
717
+ {
718
+ className: "eth-inbox-attachment-preview__image-frame",
719
+ role: "img",
720
+ "aria-label": `${attachment.name} image preview`,
721
+ children: [
722
+ /* @__PURE__ */ jsx8("span", {}),
723
+ /* @__PURE__ */ jsx8("span", {})
724
+ ]
725
+ }
726
+ );
727
+ }
728
+ if (kind === "text") {
729
+ return /* @__PURE__ */ jsx8(
730
+ "div",
731
+ {
732
+ className: "eth-inbox-attachment-preview__text",
733
+ role: "img",
734
+ "aria-label": `${attachment.name} text preview`,
735
+ children: Array.from({ length: 9 }, (_, index) => /* @__PURE__ */ jsx8("span", {}, index))
736
+ }
737
+ );
738
+ }
739
+ if (kind === "spreadsheet") {
740
+ return /* @__PURE__ */ jsx8(
741
+ "div",
742
+ {
743
+ className: "eth-inbox-attachment-preview__sheet",
744
+ role: "img",
745
+ "aria-label": `${attachment.name} spreadsheet preview`,
746
+ children: Array.from({ length: 20 }, (_, index) => /* @__PURE__ */ jsx8("span", {}, index))
747
+ }
748
+ );
749
+ }
750
+ if (kind === "pdf") {
751
+ return /* @__PURE__ */ jsxs8(
752
+ "div",
753
+ {
754
+ className: "eth-inbox-attachment-preview__document",
755
+ role: "img",
756
+ "aria-label": `${attachment.name} PDF preview`,
757
+ children: [
758
+ /* @__PURE__ */ jsxs8("div", { className: "eth-inbox-attachment-preview__document-bar", children: [
759
+ /* @__PURE__ */ jsx8("span", { children: attachment.mimeType }),
760
+ /* @__PURE__ */ jsx8("span", { children: "Page 1" })
761
+ ] }),
762
+ /* @__PURE__ */ jsxs8("div", { className: "eth-inbox-attachment-preview__page", children: [
763
+ /* @__PURE__ */ jsx8("strong", { children: attachment.name.replace(/\.[^.]+$/, "") || attachment.name }),
764
+ /* @__PURE__ */ jsx8("span", {}),
765
+ /* @__PURE__ */ jsx8("span", {}),
766
+ /* @__PURE__ */ jsx8("span", {}),
767
+ /* @__PURE__ */ jsx8("span", {}),
768
+ /* @__PURE__ */ jsx8("span", {})
769
+ ] })
770
+ ]
771
+ }
772
+ );
773
+ }
774
+ return /* @__PURE__ */ jsxs8("div", { className: "eth-inbox-attachment-preview__empty", children: [
775
+ /* @__PURE__ */ jsx8("strong", { children: "Preview unavailable" }),
776
+ /* @__PURE__ */ jsxs8("span", { children: [
777
+ attachment.mimeType,
778
+ " files are kept as attachments for download or external review."
779
+ ] })
780
+ ] });
781
+ }
782
+
783
+ // src/components/RecipientPicker.tsx
784
+ import * as React4 from "react";
785
+ import { Button as Button3, SearchInput, Tag as Tag2, TextInput as TextInput2 } from "@echothink-ui/core";
786
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
787
+ function RecipientPicker({
788
+ value = [],
789
+ onChange,
790
+ onSearch,
791
+ suggestions = [],
792
+ defaultSuggestionsOpen = false,
793
+ className,
794
+ ...props
795
+ }) {
796
+ const listboxId = React4.useId().replace(/:/g, "");
797
+ const [query, setQuery] = React4.useState("");
798
+ const [manualValue, setManualValue] = React4.useState("");
799
+ const [suggestionsOpen, setSuggestionsOpen] = React4.useState(defaultSuggestionsOpen);
800
+ const normalizedQuery = query.trim().toLocaleLowerCase();
801
+ const visibleSuggestions = normalizedQuery ? suggestions.filter(
802
+ (suggestion) => [suggestion.label, suggestion.email].some(
803
+ (field) => field.toLocaleLowerCase().includes(normalizedQuery)
804
+ )
805
+ ) : suggestions;
806
+ const showSuggestions = suggestionsOpen && (visibleSuggestions.length > 0 || Boolean(query));
807
+ const add = (email) => {
808
+ const normalizedEmail = email.trim();
809
+ if (!normalizedEmail || value.includes(normalizedEmail)) return false;
810
+ onChange?.([...value, normalizedEmail]);
811
+ setManualValue("");
812
+ setQuery("");
813
+ return true;
814
+ };
815
+ const updateQuery = (nextQuery) => {
816
+ setQuery(nextQuery);
817
+ onSearch?.(nextQuery);
818
+ setSuggestionsOpen(Boolean(nextQuery || suggestions.length));
819
+ };
820
+ return /* @__PURE__ */ jsxs9(
821
+ "div",
822
+ {
823
+ ...props,
824
+ className: `eth-inbox-recipient-picker ${className ?? ""}`,
825
+ "data-eth-component": "RecipientPicker",
826
+ onBlur: (event) => {
827
+ props.onBlur?.(event);
828
+ if (!event.currentTarget.contains(event.relatedTarget)) {
829
+ setSuggestionsOpen(false);
830
+ }
831
+ },
832
+ onKeyDown: (event) => {
833
+ props.onKeyDown?.(event);
834
+ if (!event.defaultPrevented && event.key === "Escape") {
835
+ setSuggestionsOpen(false);
836
+ }
837
+ },
838
+ children: [
839
+ /* @__PURE__ */ jsxs9("div", { className: "eth-inbox-recipient-picker__selected", "aria-label": "Selected recipients", children: [
840
+ /* @__PURE__ */ jsx9("span", { className: "eth-inbox-recipient-picker__label", children: "To" }),
841
+ /* @__PURE__ */ jsx9("div", { className: "eth-inbox-recipient-picker__chips", children: value.length ? value.map((email) => /* @__PURE__ */ jsx9(
842
+ Tag2,
843
+ {
844
+ removable: true,
845
+ onRemove: () => onChange?.(value.filter((item) => item !== email)),
846
+ children: email
847
+ },
848
+ email
849
+ )) : /* @__PURE__ */ jsx9("span", { className: "eth-inbox-recipient-picker__placeholder", children: "No recipients selected" }) })
850
+ ] }),
851
+ /* @__PURE__ */ jsx9(
852
+ SearchInput,
853
+ {
854
+ "aria-controls": showSuggestions ? listboxId : void 0,
855
+ "aria-expanded": showSuggestions,
856
+ "aria-haspopup": "listbox",
857
+ className: "eth-inbox-recipient-picker__search",
858
+ labelText: "Search recipients",
859
+ value: query,
860
+ placeholder: "Search recipients",
861
+ onFocus: () => setSuggestionsOpen(Boolean(suggestions.length)),
862
+ onChange: (event) => updateQuery(event.currentTarget.value),
863
+ onClear: () => {
864
+ updateQuery("");
865
+ setSuggestionsOpen(false);
866
+ }
867
+ }
868
+ ),
869
+ /* @__PURE__ */ jsxs9("div", { className: "eth-inbox-recipient-picker__manual", children: [
870
+ /* @__PURE__ */ jsx9(
871
+ TextInput2,
872
+ {
873
+ className: "eth-inbox-recipient-picker__manual-input",
874
+ density: "compact",
875
+ hideLabel: true,
876
+ labelText: "Recipient email",
877
+ type: "email",
878
+ value: manualValue,
879
+ placeholder: "name@company.com",
880
+ onChange: (event) => setManualValue(event.currentTarget.value),
881
+ onKeyDown: (event) => {
882
+ if (event.key === "Enter") {
883
+ event.preventDefault();
884
+ add(manualValue);
885
+ }
886
+ }
887
+ }
888
+ ),
889
+ /* @__PURE__ */ jsx9(
890
+ Button3,
891
+ {
892
+ density: "compact",
893
+ disabled: !manualValue.trim(),
894
+ intent: "primary",
895
+ onClick: () => add(manualValue),
896
+ children: "Add recipient"
897
+ }
898
+ )
899
+ ] }),
900
+ showSuggestions ? /* @__PURE__ */ jsxs9(
901
+ "div",
902
+ {
903
+ className: "eth-inbox-recipient-picker__suggestions",
904
+ id: listboxId,
905
+ role: "listbox",
906
+ "aria-label": "Recipient suggestions",
907
+ "aria-multiselectable": true,
908
+ children: [
909
+ /* @__PURE__ */ jsxs9("div", { className: "eth-inbox-recipient-picker__suggestions-header", children: [
910
+ /* @__PURE__ */ jsx9("span", { children: "Suggested recipients" }),
911
+ /* @__PURE__ */ jsxs9("strong", { children: [
912
+ visibleSuggestions.length,
913
+ " result",
914
+ visibleSuggestions.length === 1 ? "" : "s"
915
+ ] })
916
+ ] }),
917
+ visibleSuggestions.length ? /* @__PURE__ */ jsx9("ul", { className: "eth-inbox-recipient-picker__suggestions-list", children: visibleSuggestions.map((suggestion) => {
918
+ const isSelected = value.includes(suggestion.email);
919
+ return /* @__PURE__ */ jsx9("li", { children: /* @__PURE__ */ jsxs9(
920
+ "button",
921
+ {
922
+ type: "button",
923
+ role: "option",
924
+ "aria-selected": isSelected,
925
+ "aria-disabled": isSelected ? true : void 0,
926
+ onClick: () => add(suggestion.email),
927
+ children: [
928
+ /* @__PURE__ */ jsxs9("span", { className: "eth-inbox-recipient-picker__suggestion-copy", children: [
929
+ /* @__PURE__ */ jsx9("strong", { children: suggestion.label }),
930
+ /* @__PURE__ */ jsx9("span", { children: suggestion.email })
931
+ ] }),
932
+ /* @__PURE__ */ jsx9("span", { className: "eth-inbox-recipient-picker__suggestion-status", children: isSelected ? "Selected" : "Add" })
933
+ ]
934
+ }
935
+ ) }, suggestion.id);
936
+ }) }) : /* @__PURE__ */ jsx9("p", { className: "eth-inbox-recipient-picker__empty", children: "No matching recipients" })
937
+ ]
938
+ }
939
+ ) : null
940
+ ]
941
+ }
942
+ );
943
+ }
944
+
945
+ // src/components/LabelManager.tsx
946
+ import * as React5 from "react";
947
+ import { Button as Button4, FormField as FormField2, Panel, TextInput as TextInput3 } from "@echothink-ui/core";
948
+ import { EditIcon, PlusIcon } from "@echothink-ui/icons";
949
+ import { Fragment, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
950
+ function LabelManager({
951
+ labels = [],
952
+ onCreate,
953
+ onRename,
954
+ onDelete,
955
+ className,
956
+ ...props
957
+ }) {
958
+ const [newLabel, setNewLabel] = React5.useState("");
959
+ const [edits, setEdits] = React5.useState({});
960
+ const trackedLabels = labels.filter((label) => typeof label.count === "number");
961
+ const trackedMessageCount = trackedLabels.reduce((total, label) => total + (label.count ?? 0), 0);
962
+ const labelSummary = `${labels.length.toLocaleString()} ${labels.length === 1 ? "label" : "labels"}`;
963
+ const subtitle = labels.length ? trackedLabels.length ? `${labelSummary} \xB7 ${trackedMessageCount.toLocaleString()} tracked messages` : `${labelSummary} configured for mailbox categories and automation tags.` : "Create categories and automation tags for mailbox workflows.";
964
+ const submitNewLabel = (event) => {
965
+ event.preventDefault();
966
+ const nextLabel = newLabel.trim();
967
+ if (!nextLabel || !onCreate) return;
968
+ onCreate(nextLabel);
969
+ setNewLabel("");
970
+ };
971
+ return /* @__PURE__ */ jsxs10(
972
+ Panel,
973
+ {
974
+ ...props,
975
+ className: `eth-inbox-label-manager ${className ?? ""}`,
976
+ title: "Labels",
977
+ subtitle,
978
+ "data-eth-component": "LabelManager",
979
+ children: [
980
+ labels.length ? /* @__PURE__ */ jsxs10("div", { className: "eth-inbox-label-manager__list", role: "table", "aria-label": "Managed labels", children: [
981
+ /* @__PURE__ */ jsxs10("div", { className: "eth-inbox-label-manager__table-head", role: "row", children: [
982
+ /* @__PURE__ */ jsx10("span", { role: "columnheader", children: "Label" }),
983
+ /* @__PURE__ */ jsx10("span", { role: "columnheader", children: "Messages" }),
984
+ /* @__PURE__ */ jsx10("span", { role: "columnheader", children: "Actions" })
985
+ ] }),
986
+ labels.map((label) => {
987
+ const draft = edits[label.id] ?? label.label;
988
+ const trimmedDraft = draft.trim();
989
+ const countLabel = typeof label.count === "number" ? `${label.count.toLocaleString()} ${label.count === 1 ? "message" : "messages"}` : "Message count not tracked";
990
+ return /* @__PURE__ */ jsxs10("div", { className: "eth-inbox-label-manager__row", role: "row", children: [
991
+ /* @__PURE__ */ jsx10("div", { className: "eth-inbox-label-manager__name-cell", role: "cell", children: /* @__PURE__ */ jsx10(
992
+ TextInput3,
993
+ {
994
+ "aria-label": `Label name for ${label.label}`,
995
+ density: "compact",
996
+ placeholder: "Label name",
997
+ value: draft,
998
+ onChange: (event) => setEdits((current) => ({
999
+ ...current,
1000
+ [label.id]: event.currentTarget.value
1001
+ }))
1002
+ }
1003
+ ) }),
1004
+ /* @__PURE__ */ jsx10(
1005
+ "div",
1006
+ {
1007
+ className: "eth-inbox-label-manager__count-cell",
1008
+ role: "cell",
1009
+ "aria-label": countLabel,
1010
+ children: typeof label.count === "number" ? /* @__PURE__ */ jsxs10(Fragment, { children: [
1011
+ /* @__PURE__ */ jsx10("strong", { children: label.count.toLocaleString() }),
1012
+ /* @__PURE__ */ jsx10("span", { children: label.count === 1 ? "message" : "messages" })
1013
+ ] }) : /* @__PURE__ */ jsx10("span", { className: "eth-inbox-label-manager__count-muted", children: "Not tracked" })
1014
+ }
1015
+ ),
1016
+ /* @__PURE__ */ jsxs10("div", { className: "eth-inbox-label-manager__actions", role: "cell", children: [
1017
+ /* @__PURE__ */ jsx10(
1018
+ Button4,
1019
+ {
1020
+ density: "compact",
1021
+ disabled: !onRename || !trimmedDraft,
1022
+ icon: /* @__PURE__ */ jsx10(EditIcon, { size: 16 }),
1023
+ intent: "secondary",
1024
+ onClick: () => {
1025
+ if (trimmedDraft) onRename?.(label.id, trimmedDraft);
1026
+ },
1027
+ children: "Rename"
1028
+ }
1029
+ ),
1030
+ /* @__PURE__ */ jsx10(
1031
+ Button4,
1032
+ {
1033
+ density: "compact",
1034
+ disabled: !onDelete,
1035
+ intent: "danger",
1036
+ onClick: () => onDelete?.(label.id),
1037
+ children: "Delete"
1038
+ }
1039
+ )
1040
+ ] })
1041
+ ] }, label.id);
1042
+ })
1043
+ ] }) : /* @__PURE__ */ jsx10("p", { className: "eth-inbox-label-manager__empty", children: "No labels configured. Create a label to route mailbox views and automation rules." }),
1044
+ /* @__PURE__ */ jsxs10("form", { className: "eth-inbox-label-manager__create", onSubmit: submitNewLabel, children: [
1045
+ /* @__PURE__ */ jsx10(
1046
+ FormField2,
1047
+ {
1048
+ label: "New label",
1049
+ helperText: "Use concise names for categories, filters, and automation rules.",
1050
+ children: /* @__PURE__ */ jsx10(
1051
+ TextInput3,
1052
+ {
1053
+ density: "compact",
1054
+ placeholder: "e.g. renewal-risk",
1055
+ value: newLabel,
1056
+ onChange: (event) => setNewLabel(event.currentTarget.value)
1057
+ }
1058
+ )
1059
+ }
1060
+ ),
1061
+ /* @__PURE__ */ jsx10(
1062
+ Button4,
1063
+ {
1064
+ disabled: !onCreate || !newLabel.trim(),
1065
+ icon: /* @__PURE__ */ jsx10(PlusIcon, { size: 16 }),
1066
+ type: "submit",
1067
+ children: "Create"
1068
+ }
1069
+ )
1070
+ ] })
1071
+ ]
1072
+ }
1073
+ );
1074
+ }
1075
+
1076
+ // src/components/MessageSearch.tsx
1077
+ import { IconButton as IconButton2, SearchInput as SearchInput2 } from "@echothink-ui/core";
1078
+ import { ChevronRightIcon } from "@echothink-ui/icons";
1079
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1080
+ function MessageSearch({
1081
+ value = "",
1082
+ onChange,
1083
+ placeholder = "Search messages",
1084
+ resultCount,
1085
+ activeResultIndex = 0,
1086
+ onPreviousResult,
1087
+ onNextResult,
1088
+ className,
1089
+ role,
1090
+ "aria-label": ariaLabel,
1091
+ ...props
1092
+ }) {
1093
+ const hasResultCount = typeof resultCount === "number";
1094
+ const normalizedResultCount = hasResultCount && Number.isFinite(resultCount) ? Math.max(0, Math.trunc(resultCount)) : 0;
1095
+ const normalizedResultIndex = Number.isFinite(activeResultIndex) ? Math.trunc(activeResultIndex) : 0;
1096
+ const hasResults = normalizedResultCount > 0;
1097
+ const currentResult = hasResults ? Math.min(Math.max(normalizedResultIndex, 0), normalizedResultCount - 1) + 1 : 0;
1098
+ const canGoPrevious = hasResults && currentResult > 1 && Boolean(onPreviousResult);
1099
+ const canGoNext = hasResults && currentResult < normalizedResultCount && Boolean(onNextResult);
1100
+ const resultNoun = normalizedResultCount === 1 ? "result" : "results";
1101
+ const resultLabel = hasResults ? `${currentResult} of ${normalizedResultCount} ${resultNoun}` : "No results";
1102
+ return /* @__PURE__ */ jsxs11(
1103
+ "div",
1104
+ {
1105
+ ...props,
1106
+ className: ["eth-inbox-search", className].filter(Boolean).join(" "),
1107
+ "data-eth-component": "MessageSearch",
1108
+ role: role ?? "search",
1109
+ "aria-label": ariaLabel ?? "Message search",
1110
+ children: [
1111
+ /* @__PURE__ */ jsx11("div", { className: "eth-inbox-search__input", children: /* @__PURE__ */ jsx11(
1112
+ SearchInput2,
1113
+ {
1114
+ value,
1115
+ placeholder,
1116
+ labelText: placeholder,
1117
+ onChange: (event) => onChange?.(event.currentTarget.value),
1118
+ onClear: () => onChange?.(""),
1119
+ className: "eth-inbox-search__control"
1120
+ }
1121
+ ) }),
1122
+ hasResultCount ? /* @__PURE__ */ jsxs11("div", { className: "eth-inbox-search__results", children: [
1123
+ /* @__PURE__ */ jsx11("span", { className: "eth-inbox-search__count", "aria-live": "polite", children: resultLabel }),
1124
+ /* @__PURE__ */ jsxs11(
1125
+ "div",
1126
+ {
1127
+ className: "eth-inbox-search__nav",
1128
+ role: "group",
1129
+ "aria-label": "Search result navigation",
1130
+ children: [
1131
+ /* @__PURE__ */ jsx11(
1132
+ IconButton2,
1133
+ {
1134
+ className: "eth-inbox-search__nav-button eth-inbox-search__nav-button--previous",
1135
+ density: "compact",
1136
+ intent: "ghost",
1137
+ label: "Previous result",
1138
+ icon: /* @__PURE__ */ jsx11(ChevronRightIcon, { size: 16 }),
1139
+ disabled: !canGoPrevious,
1140
+ onClick: onPreviousResult
1141
+ }
1142
+ ),
1143
+ /* @__PURE__ */ jsx11(
1144
+ IconButton2,
1145
+ {
1146
+ className: "eth-inbox-search__nav-button",
1147
+ density: "compact",
1148
+ intent: "ghost",
1149
+ label: "Next result",
1150
+ icon: /* @__PURE__ */ jsx11(ChevronRightIcon, { size: 16 }),
1151
+ disabled: !canGoNext,
1152
+ onClick: onNextResult
1153
+ }
1154
+ )
1155
+ ]
1156
+ }
1157
+ )
1158
+ ] }) : null
1159
+ ]
1160
+ }
1161
+ );
1162
+ }
1163
+
1164
+ // src/components/MessageFilterBar.tsx
1165
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1166
+ var filterKindLabels = {
1167
+ priority: "Priority",
1168
+ sender: "Sender",
1169
+ date: "Date",
1170
+ label: "Label",
1171
+ unread: "Read",
1172
+ status: "Status"
1173
+ };
1174
+ function MessageFilterBar({
1175
+ filters = [],
1176
+ onToggle,
1177
+ className,
1178
+ "aria-label": ariaLabel = "Message filters",
1179
+ ...props
1180
+ }) {
1181
+ return /* @__PURE__ */ jsx12(
1182
+ "div",
1183
+ {
1184
+ ...props,
1185
+ className: `eth-inbox-filter-bar ${className ?? ""}`,
1186
+ "data-eth-component": "MessageFilterBar",
1187
+ role: "toolbar",
1188
+ "aria-label": ariaLabel,
1189
+ children: filters.map((filter) => {
1190
+ const kindLabel = filter.kind ? filterKindLabels[filter.kind] : void 0;
1191
+ const accessibleLabel = kindLabel ? `${kindLabel}: ${filter.label}` : filter.label;
1192
+ return /* @__PURE__ */ jsxs12(
1193
+ "button",
1194
+ {
1195
+ type: "button",
1196
+ className: `eth-inbox-filter-bar__chip ${filter.active ? "eth-inbox-filter-bar__chip--active" : ""} ${filter.disabled ? "eth-inbox-filter-bar__chip--disabled" : ""}`,
1197
+ "aria-label": accessibleLabel,
1198
+ "aria-pressed": Boolean(filter.active),
1199
+ "data-filter-kind": filter.kind,
1200
+ disabled: filter.disabled,
1201
+ onClick: () => onToggle?.(filter.id, !Boolean(filter.active)),
1202
+ children: [
1203
+ kindLabel ? /* @__PURE__ */ jsx12("span", { className: "eth-inbox-filter-bar__kind", "aria-hidden": "true", children: kindLabel }) : null,
1204
+ /* @__PURE__ */ jsx12("span", { className: "eth-inbox-filter-bar__label", children: filter.label })
1205
+ ]
1206
+ },
1207
+ filter.id
1208
+ );
1209
+ })
1210
+ }
1211
+ );
1212
+ }
1213
+
1214
+ // src/components/PriorityInboxView.tsx
1215
+ import * as React6 from "react";
1216
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1217
+ function PriorityInboxView({
1218
+ groups = [],
1219
+ selectedThreadId,
1220
+ onSelect,
1221
+ className,
1222
+ ...props
1223
+ }) {
1224
+ const hasGroups = groups.length > 0;
1225
+ const idBase = React6.useId();
1226
+ return /* @__PURE__ */ jsx13(
1227
+ "div",
1228
+ {
1229
+ ...props,
1230
+ className: `eth-inbox-priority ${className ?? ""}`,
1231
+ "data-eth-component": "PriorityInboxView",
1232
+ children: hasGroups ? groups.map((group, index) => {
1233
+ const headingId = `${idBase}-group-${index}-heading`;
1234
+ return /* @__PURE__ */ jsxs13(
1235
+ "section",
1236
+ {
1237
+ className: "eth-inbox-priority__group",
1238
+ "aria-labelledby": headingId,
1239
+ children: [
1240
+ /* @__PURE__ */ jsxs13("header", { className: "eth-inbox-priority__group-header", children: [
1241
+ /* @__PURE__ */ jsxs13("div", { className: "eth-inbox-priority__heading", children: [
1242
+ /* @__PURE__ */ jsx13("h3", { id: headingId, children: group.title }),
1243
+ group.description ? /* @__PURE__ */ jsx13("p", { className: "eth-inbox-priority__description", children: group.description }) : null
1244
+ ] }),
1245
+ /* @__PURE__ */ jsx13("span", { className: "eth-inbox-priority__count", children: formatThreadCount(group.threads.length) })
1246
+ ] }),
1247
+ /* @__PURE__ */ jsx13(
1248
+ MessageList,
1249
+ {
1250
+ threads: group.threads,
1251
+ selectedThreadId,
1252
+ onSelect
1253
+ }
1254
+ )
1255
+ ]
1256
+ },
1257
+ group.id
1258
+ );
1259
+ }) : /* @__PURE__ */ jsx13("div", { className: "eth-inbox-priority__empty", role: "status", "aria-label": "No priority threads", children: "No priority threads" })
1260
+ }
1261
+ );
1262
+ }
1263
+ function formatThreadCount(count) {
1264
+ return `${count} ${count === 1 ? "thread" : "threads"}`;
1265
+ }
1266
+
1267
+ // src/components/EmailAutomationRulePanel.tsx
1268
+ import { Badge as Badge4, Button as Button5, Panel as Panel2, Toggle } from "@echothink-ui/core";
1269
+ import { EditIcon as EditIcon2 } from "@echothink-ui/icons";
1270
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
1271
+ function EmailAutomationRulePanel({
1272
+ rules = [],
1273
+ onToggle,
1274
+ onEdit,
1275
+ className,
1276
+ ...props
1277
+ }) {
1278
+ const enabledCount = rules.reduce((count, rule) => count + (rule.enabled ? 1 : 0), 0);
1279
+ const ruleCountLabel = `${rules.length} automation ${rules.length === 1 ? "rule" : "rules"}`;
1280
+ const subtitle = rules.length ? `${enabledCount} of ${ruleCountLabel} enabled` : "Create routing, drafting, and mailbox automation rules.";
1281
+ return /* @__PURE__ */ jsx14(
1282
+ Panel2,
1283
+ {
1284
+ ...props,
1285
+ className: `eth-inbox-rules ${className ?? ""}`,
1286
+ title: "Automation rules",
1287
+ subtitle,
1288
+ "data-eth-component": "EmailAutomationRulePanel",
1289
+ children: rules.length ? /* @__PURE__ */ jsx14("div", { className: "eth-inbox-rules__list", role: "list", children: rules.map((rule) => {
1290
+ const headingId = `eth-inbox-rule-${rule.id.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
1291
+ return /* @__PURE__ */ jsxs14(
1292
+ "article",
1293
+ {
1294
+ "aria-labelledby": headingId,
1295
+ className: `eth-inbox-rules__item ${rule.enabled ? "eth-inbox-rules__item--enabled" : "eth-inbox-rules__item--paused"}`,
1296
+ role: "listitem",
1297
+ children: [
1298
+ /* @__PURE__ */ jsxs14("div", { className: "eth-inbox-rules__content", children: [
1299
+ /* @__PURE__ */ jsxs14("header", { className: "eth-inbox-rules__item-header", children: [
1300
+ /* @__PURE__ */ jsx14("h4", { id: headingId, children: rule.name }),
1301
+ /* @__PURE__ */ jsx14(Badge4, { severity: rule.enabled ? "success" : "neutral", children: rule.enabled ? "Enabled" : "Paused" })
1302
+ ] }),
1303
+ /* @__PURE__ */ jsxs14("dl", { className: "eth-inbox-rules__definition", children: [
1304
+ /* @__PURE__ */ jsxs14("div", { children: [
1305
+ /* @__PURE__ */ jsx14("dt", { children: "Trigger" }),
1306
+ /* @__PURE__ */ jsx14("dd", { children: rule.conditions })
1307
+ ] }),
1308
+ /* @__PURE__ */ jsxs14("div", { children: [
1309
+ /* @__PURE__ */ jsx14("dt", { children: "Action" }),
1310
+ /* @__PURE__ */ jsx14("dd", { children: rule.actions })
1311
+ ] })
1312
+ ] })
1313
+ ] }),
1314
+ /* @__PURE__ */ jsxs14("div", { className: "eth-inbox-rules__controls", children: [
1315
+ /* @__PURE__ */ jsx14(
1316
+ Toggle,
1317
+ {
1318
+ checked: rule.enabled,
1319
+ className: "eth-inbox-rules__toggle",
1320
+ disabled: !onToggle,
1321
+ hideLabel: true,
1322
+ label: `Automation status for ${rule.name}`,
1323
+ offLabel: "Paused",
1324
+ onChange: (event) => onToggle?.(rule.id, event.currentTarget.checked),
1325
+ onLabel: "Enabled"
1326
+ }
1327
+ ),
1328
+ /* @__PURE__ */ jsx14(
1329
+ Button5,
1330
+ {
1331
+ "aria-label": `Edit ${rule.name}`,
1332
+ density: "compact",
1333
+ disabled: !onEdit,
1334
+ icon: /* @__PURE__ */ jsx14(EditIcon2, { size: 16 }),
1335
+ intent: "secondary",
1336
+ onClick: () => onEdit?.(rule.id),
1337
+ children: "Edit"
1338
+ }
1339
+ )
1340
+ ] })
1341
+ ]
1342
+ },
1343
+ rule.id
1344
+ );
1345
+ }) }) : /* @__PURE__ */ jsx14("p", { className: "eth-inbox-rules__empty", children: "No automation rules configured." })
1346
+ }
1347
+ );
1348
+ }
1349
+
1350
+ // src/components/AgentDraftReviewPanel.tsx
1351
+ import { Badge as Badge5, Button as Button6, Panel as Panel3, Tag as Tag3 } from "@echothink-ui/core";
1352
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
1353
+ function formatDraftTimestamp(value) {
1354
+ if (!value) return null;
1355
+ const date = new Date(value);
1356
+ if (Number.isNaN(date.getTime())) return value;
1357
+ return new Intl.DateTimeFormat("en-US", {
1358
+ month: "short",
1359
+ day: "numeric",
1360
+ hour: "numeric",
1361
+ minute: "2-digit"
1362
+ }).format(date);
1363
+ }
1364
+ function AgentDraftReviewPanel({
1365
+ draft,
1366
+ onApprove,
1367
+ onEdit,
1368
+ onReject,
1369
+ className,
1370
+ ...props
1371
+ }) {
1372
+ const formattedDate = formatDraftTimestamp(draft?.date);
1373
+ const hasDraft = Boolean(draft);
1374
+ return /* @__PURE__ */ jsxs15(
1375
+ Panel3,
1376
+ {
1377
+ ...props,
1378
+ className: `eth-inbox-agent-draft ${className ?? ""}`,
1379
+ title: "Agent draft review",
1380
+ subtitle: "Validate the generated response, source evidence, and approval direction before sending.",
1381
+ "data-eth-component": "AgentDraftReviewPanel",
1382
+ children: [
1383
+ draft ? /* @__PURE__ */ jsxs15("div", { className: "eth-inbox-agent-draft__content", children: [
1384
+ /* @__PURE__ */ jsxs15("div", { className: "eth-inbox-agent-draft__status", children: [
1385
+ /* @__PURE__ */ jsx15(Badge5, { severity: "info", children: draft.statusLabel ?? "Ready for review" }),
1386
+ /* @__PURE__ */ jsx15("span", { children: "Generated from inbound thread and policy context" }),
1387
+ formattedDate ? /* @__PURE__ */ jsxs15("time", { dateTime: draft.date, children: [
1388
+ "Updated ",
1389
+ formattedDate
1390
+ ] }) : null
1391
+ ] }),
1392
+ /* @__PURE__ */ jsxs15("dl", { className: "eth-inbox-agent-draft__meta", children: [
1393
+ /* @__PURE__ */ jsxs15("div", { children: [
1394
+ /* @__PURE__ */ jsx15("dt", { children: "Subject" }),
1395
+ /* @__PURE__ */ jsx15("dd", { children: draft.subject ?? "No subject" })
1396
+ ] }),
1397
+ /* @__PURE__ */ jsxs15("div", { children: [
1398
+ /* @__PURE__ */ jsx15("dt", { children: "Requested by" }),
1399
+ /* @__PURE__ */ jsx15("dd", { children: draft.from || "Unknown sender" })
1400
+ ] }),
1401
+ /* @__PURE__ */ jsxs15("div", { children: [
1402
+ /* @__PURE__ */ jsx15("dt", { children: "Recipients" }),
1403
+ /* @__PURE__ */ jsx15("dd", { children: draft.to?.length ? draft.to.join(", ") : "No recipients" })
1404
+ ] })
1405
+ ] }),
1406
+ /* @__PURE__ */ jsxs15("section", { className: "eth-inbox-agent-draft__section", "aria-label": "Proposed response", children: [
1407
+ /* @__PURE__ */ jsx15("div", { className: "eth-inbox-agent-draft__section-header", children: /* @__PURE__ */ jsx15("span", { children: "Proposed response" }) }),
1408
+ /* @__PURE__ */ jsx15("div", { className: "eth-inbox-agent-draft__body", children: draft.body })
1409
+ ] }),
1410
+ draft.rationale ? /* @__PURE__ */ jsxs15("section", { className: "eth-inbox-agent-draft__rationale", "aria-label": "Agent rationale", children: [
1411
+ /* @__PURE__ */ jsx15("span", { children: "Agent rationale" }),
1412
+ /* @__PURE__ */ jsx15("div", { className: "eth-inbox-agent-draft__rationale-body", children: draft.rationale })
1413
+ ] }) : null,
1414
+ draft.evidence?.length ? /* @__PURE__ */ jsxs15("section", { className: "eth-inbox-agent-draft__evidence", "aria-label": "Source evidence", children: [
1415
+ /* @__PURE__ */ jsx15("span", { children: "Source evidence" }),
1416
+ /* @__PURE__ */ jsx15("div", { className: "eth-inbox-agent-draft__evidence-list", children: draft.evidence.map(
1417
+ (item) => item.href ? /* @__PURE__ */ jsx15("a", { href: item.href, children: /* @__PURE__ */ jsx15(Tag3, { children: item.label }) }, item.id) : /* @__PURE__ */ jsx15(Tag3, { children: item.label }, item.id)
1418
+ ) })
1419
+ ] }) : null
1420
+ ] }) : /* @__PURE__ */ jsxs15("div", { className: "eth-inbox-agent-draft__empty", role: "status", children: [
1421
+ /* @__PURE__ */ jsx15("strong", { children: "No draft selected" }),
1422
+ /* @__PURE__ */ jsx15("p", { children: "Select an agent-generated response to review its evidence and approval options." })
1423
+ ] }),
1424
+ /* @__PURE__ */ jsxs15("div", { className: "eth-inbox-agent-draft__actions", children: [
1425
+ /* @__PURE__ */ jsx15(Button6, { type: "button", disabled: !hasDraft, onClick: onApprove, children: "Approve draft" }),
1426
+ /* @__PURE__ */ jsx15(Button6, { type: "button", intent: "secondary", disabled: !hasDraft, onClick: onEdit, children: "Edit draft" }),
1427
+ /* @__PURE__ */ jsx15(Button6, { type: "button", intent: "danger", disabled: !hasDraft, onClick: onReject, children: "Reject draft" })
1428
+ ] })
1429
+ ]
1430
+ }
1431
+ );
1432
+ }
1433
+
1434
+ // src/components/ApprovalToSendPanel.tsx
1435
+ import * as React7 from "react";
1436
+ import { Badge as Badge6, Button as Button7, Panel as Panel4, Textarea as Textarea2 } from "@echothink-ui/core";
1437
+ import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
1438
+ function ApprovalToSendPanel({
1439
+ draft,
1440
+ recipients = [],
1441
+ riskLevel = "low",
1442
+ policyRef,
1443
+ onApprove,
1444
+ onReject,
1445
+ className,
1446
+ ...props
1447
+ }) {
1448
+ const [reason, setReason] = React7.useState("");
1449
+ const toRecipients = recipients.length ? recipients : draft?.to ?? [];
1450
+ const ccRecipients = draft?.cc ?? [];
1451
+ const bccRecipients = draft?.bcc ?? [];
1452
+ const subject = draft?.subject?.trim() || "No subject";
1453
+ const body = draft?.body?.trim() || "No message body provided.";
1454
+ const riskSeverity = riskLevel === "critical" || riskLevel === "high" ? "danger" : riskLevel === "medium" ? "warning" : "info";
1455
+ const riskLabel = `${riskLevel.charAt(0).toUpperCase()}${riskLevel.slice(1)} risk`;
1456
+ const recipientCount = recipients.length || toRecipients.length + ccRecipients.length + bccRecipients.length;
1457
+ const recipientKind = recipients.length ? "external recipient" : "recipient";
1458
+ const recipientSummary = recipientCount === 1 ? `1 ${recipientKind}` : `${recipientCount || "No"} ${recipientKind}s`;
1459
+ const formatRecipients2 = (values) => values.length ? values.join(", ") : "Not specified";
1460
+ return /* @__PURE__ */ jsxs16(
1461
+ Panel4,
1462
+ {
1463
+ ...props,
1464
+ className: `eth-inbox-send-approval eth-inbox-send-approval--${riskLevel} ${className ?? ""}`,
1465
+ title: "Approval required",
1466
+ subtitle: "Review this outbound message before it is sent.",
1467
+ "data-eth-component": "ApprovalToSendPanel",
1468
+ children: [
1469
+ /* @__PURE__ */ jsxs16("div", { className: "eth-inbox-send-approval__status", children: [
1470
+ /* @__PURE__ */ jsxs16("div", { className: "eth-inbox-send-approval__summary", children: [
1471
+ /* @__PURE__ */ jsx16(Badge6, { severity: riskSeverity, children: riskLabel }),
1472
+ policyRef ? /* @__PURE__ */ jsx16("span", { className: "eth-inbox-send-approval__policy", children: policyRef }) : null
1473
+ ] }),
1474
+ /* @__PURE__ */ jsx16("span", { className: "eth-inbox-send-approval__state", children: "Awaiting approval" })
1475
+ ] }),
1476
+ /* @__PURE__ */ jsxs16(
1477
+ "section",
1478
+ {
1479
+ className: "eth-inbox-send-approval__message",
1480
+ "aria-label": "Outbound message for approval",
1481
+ children: [
1482
+ /* @__PURE__ */ jsx16("header", { className: "eth-inbox-send-approval__message-header", children: /* @__PURE__ */ jsxs16("div", { children: [
1483
+ /* @__PURE__ */ jsx16("h4", { children: "Outbound message" }),
1484
+ /* @__PURE__ */ jsx16("p", { children: recipientSummary })
1485
+ ] }) }),
1486
+ /* @__PURE__ */ jsxs16("dl", { className: "eth-inbox-send-approval__meta", children: [
1487
+ /* @__PURE__ */ jsxs16("div", { children: [
1488
+ /* @__PURE__ */ jsx16("dt", { children: "To" }),
1489
+ /* @__PURE__ */ jsx16("dd", { children: formatRecipients2(toRecipients) })
1490
+ ] }),
1491
+ ccRecipients.length ? /* @__PURE__ */ jsxs16("div", { children: [
1492
+ /* @__PURE__ */ jsx16("dt", { children: "Cc" }),
1493
+ /* @__PURE__ */ jsx16("dd", { children: formatRecipients2(ccRecipients) })
1494
+ ] }) : null,
1495
+ bccRecipients.length ? /* @__PURE__ */ jsxs16("div", { children: [
1496
+ /* @__PURE__ */ jsx16("dt", { children: "Bcc" }),
1497
+ /* @__PURE__ */ jsx16("dd", { children: formatRecipients2(bccRecipients) })
1498
+ ] }) : null,
1499
+ /* @__PURE__ */ jsxs16("div", { children: [
1500
+ /* @__PURE__ */ jsx16("dt", { children: "Subject" }),
1501
+ /* @__PURE__ */ jsx16("dd", { children: subject })
1502
+ ] })
1503
+ ] }),
1504
+ /* @__PURE__ */ jsxs16("div", { className: "eth-inbox-send-approval__message-body", children: [
1505
+ /* @__PURE__ */ jsx16("span", { children: "Message body" }),
1506
+ /* @__PURE__ */ jsx16("p", { children: body })
1507
+ ] })
1508
+ ]
1509
+ }
1510
+ ),
1511
+ /* @__PURE__ */ jsx16("div", { className: "eth-inbox-send-approval__decision", children: /* @__PURE__ */ jsx16(
1512
+ Textarea2,
1513
+ {
1514
+ value: reason,
1515
+ labelText: "Decision note",
1516
+ helperText: "Optional for approval. Include the policy reason when rejecting.",
1517
+ placeholder: "Add an approval or rejection reason",
1518
+ onChange: (event) => setReason(event.currentTarget.value)
1519
+ }
1520
+ ) }),
1521
+ /* @__PURE__ */ jsxs16("div", { className: "eth-inbox-send-approval__actions", children: [
1522
+ /* @__PURE__ */ jsx16(Button7, { intent: "danger", onClick: () => onReject?.(reason || void 0), children: "Reject" }),
1523
+ /* @__PURE__ */ jsx16(Button7, { onClick: () => onApprove?.(reason || void 0), children: "Approve send" })
1524
+ ] })
1525
+ ]
1526
+ }
1527
+ );
1528
+ }
1529
+
1530
+ // src/components/ThreadSummaryPanel.tsx
1531
+ import { Badge as Badge7, Panel as Panel5, Tag as Tag4 } from "@echothink-ui/core";
1532
+ import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
1533
+ function ThreadSummaryPanel({
1534
+ summary,
1535
+ className,
1536
+ ...props
1537
+ }) {
1538
+ const citations = summary?.citations ?? [];
1539
+ const citationCount = citations.length;
1540
+ return /* @__PURE__ */ jsx17(
1541
+ Panel5,
1542
+ {
1543
+ ...props,
1544
+ className: `eth-inbox-thread-summary ${className ?? ""}`,
1545
+ title: "Thread summary",
1546
+ subtitle: "Agent-generated recap with source references.",
1547
+ "data-eth-component": "ThreadSummaryPanel",
1548
+ children: summary ? /* @__PURE__ */ jsxs17("div", { className: "eth-inbox-thread-summary__content", children: [
1549
+ /* @__PURE__ */ jsxs17(
1550
+ "div",
1551
+ {
1552
+ className: "eth-inbox-thread-summary__metadata",
1553
+ role: "group",
1554
+ "aria-label": "Summary metadata",
1555
+ children: [
1556
+ /* @__PURE__ */ jsx17(Badge7, { severity: "info", children: "Agent generated" }),
1557
+ /* @__PURE__ */ jsx17("span", { children: formatCitationCount(citationCount) })
1558
+ ]
1559
+ }
1560
+ ),
1561
+ /* @__PURE__ */ jsxs17("section", { className: "eth-inbox-thread-summary__summary", "aria-label": "Generated summary", children: [
1562
+ /* @__PURE__ */ jsx17("span", { className: "eth-inbox-thread-summary__section-label", children: "Summary" }),
1563
+ /* @__PURE__ */ jsx17("div", { className: "eth-inbox-thread-summary__summary-body", children: summary.text })
1564
+ ] }),
1565
+ citations.length ? /* @__PURE__ */ jsxs17("section", { className: "eth-inbox-thread-summary__sources", "aria-label": "Source citations", children: [
1566
+ /* @__PURE__ */ jsx17("span", { className: "eth-inbox-thread-summary__section-label", children: "Source citations" }),
1567
+ /* @__PURE__ */ jsx17("ul", { className: "eth-inbox-thread-summary__source-list", children: citations.map((citation) => /* @__PURE__ */ jsx17("li", { className: "eth-inbox-thread-summary__source-item", children: /* @__PURE__ */ jsx17(CitationTag, { citation }) }, citation.id)) })
1568
+ ] }) : /* @__PURE__ */ jsx17("div", { className: "eth-inbox-thread-summary__no-sources", role: "status", children: "No citations attached." })
1569
+ ] }) : /* @__PURE__ */ jsxs17("div", { className: "eth-inbox-thread-summary__empty", role: "status", children: [
1570
+ /* @__PURE__ */ jsx17("strong", { children: "No generated summary" }),
1571
+ /* @__PURE__ */ jsx17("p", { children: "Summaries and source citations appear here after the agent reviews the conversation." })
1572
+ ] })
1573
+ }
1574
+ );
1575
+ }
1576
+ function CitationTag({ citation }) {
1577
+ const referenceLabel = citation.messageRef ? `${citation.label}, message ${citation.messageRef}` : citation.label;
1578
+ const tag = /* @__PURE__ */ jsx17(
1579
+ Tag4,
1580
+ {
1581
+ className: "eth-inbox-thread-summary__source-token",
1582
+ "aria-label": referenceLabel,
1583
+ title: referenceLabel,
1584
+ "data-message-ref": citation.messageRef,
1585
+ children: citation.label
1586
+ }
1587
+ );
1588
+ if (!citation.href) {
1589
+ return /* @__PURE__ */ jsx17("span", { className: "eth-inbox-thread-summary__source-reference", children: tag });
1590
+ }
1591
+ return /* @__PURE__ */ jsx17(
1592
+ "a",
1593
+ {
1594
+ className: "eth-inbox-thread-summary__source-link",
1595
+ href: citation.href,
1596
+ "aria-label": referenceLabel,
1597
+ children: tag
1598
+ }
1599
+ );
1600
+ }
1601
+ function formatCitationCount(count) {
1602
+ return `${count} ${count === 1 ? "citation" : "citations"}`;
1603
+ }
1604
+
1605
+ // src/index.tsx
1606
+ var InboxComponentNames = [
1607
+ "InboxShell",
1608
+ "MailboxFolderList",
1609
+ "MessageList",
1610
+ "MessageThread",
1611
+ "MessageComposer",
1612
+ "MessagePreview",
1613
+ "AttachmentList",
1614
+ "AttachmentPreview",
1615
+ "RecipientPicker",
1616
+ "LabelManager",
1617
+ "MessageSearch",
1618
+ "MessageFilterBar",
1619
+ "PriorityInboxView",
1620
+ "EmailAutomationRulePanel",
1621
+ "AgentDraftReviewPanel",
1622
+ "ApprovalToSendPanel",
1623
+ "ThreadSummaryPanel"
1624
+ ];
1625
+ export {
1626
+ AgentDraftReviewPanel,
1627
+ ApprovalToSendPanel,
1628
+ AttachmentList,
1629
+ AttachmentPreview,
1630
+ EmailAutomationRulePanel,
1631
+ InboxComponentNames,
1632
+ InboxShell,
1633
+ LabelManager,
1634
+ MailboxFolderList,
1635
+ MessageComposer,
1636
+ MessageFilterBar,
1637
+ MessageList,
1638
+ MessagePreview,
1639
+ MessageSearch,
1640
+ MessageThread,
1641
+ PriorityInboxView,
1642
+ RecipientPicker,
1643
+ ThreadSummaryPanel
1644
+ };
1645
+ //# sourceMappingURL=index.js.map