@paramms/chat-widget 1.0.5 → 1.0.7

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.
@@ -0,0 +1,62 @@
1
+ /**
2
+ * chatlist.ts — standalone chat list widget.
3
+ *
4
+ * Completely separate from mount() / the chat widget.
5
+ * Shows all conversations for a given userId / guest on a profile.
6
+ * Tapping a row fires onSelect(entry) — the caller decides what to do
7
+ * (navigate to a new page, open a ChatWidget inline, etc.)
8
+ *
9
+ * Usage (vanilla):
10
+ * import { mountChatList } from '@paramms/chat-widget/chatlist'
11
+ * const handle = mountChatList({
12
+ * el: document.getElementById('chat-list'),
13
+ * url: 'wss://api.paramms.com/ws',
14
+ * profileId: 'p_usedcars',
15
+ * userId: currentUser.id, // optional — uses localStorage UID if omitted
16
+ * onSelect: (entry) => {
17
+ * window.location.href = `/listings/${entry.subjectId}#chat`
18
+ * },
19
+ * })
20
+ * handle.refresh() // manually re-fetch the list
21
+ * handle.close() // unmount and clean up
22
+ */
23
+ export interface ChatListEntry {
24
+ id: string;
25
+ subjectId?: string;
26
+ subjectTitle?: string;
27
+ state: string;
28
+ updatedAt: number;
29
+ lastSeq?: number;
30
+ lastMessage?: string;
31
+ }
32
+ export interface ChatListOptions {
33
+ /** Mount target element */
34
+ el: HTMLElement;
35
+ /** Relay WebSocket URL — e.g. wss://api.paramms.com/ws */
36
+ url: string;
37
+ /** Profile ID to scope conversations to */
38
+ profileId: string;
39
+ /** Your logged-in user's stable ID. Omit for anonymous (uses localStorage UID) */
40
+ userId?: string;
41
+ /** Called when the user taps a conversation row */
42
+ onSelect: (entry: ChatListEntry) => void;
43
+ /** Brand colour hex — default '#f5713c' */
44
+ accent?: string;
45
+ /** i18n overrides */
46
+ i18n?: {
47
+ title?: string;
48
+ search?: string;
49
+ empty?: string;
50
+ unread?: string;
51
+ all?: string;
52
+ error?: string;
53
+ };
54
+ }
55
+ export interface ChatListHandle {
56
+ /** Re-fetch and re-render the list */
57
+ refresh(): void;
58
+ /** Unmount and clean up */
59
+ close(): void;
60
+ }
61
+ /** Mount a standalone chat list widget. */
62
+ export declare function mountChatList(opts: ChatListOptions): ChatListHandle;
@@ -0,0 +1,124 @@
1
+ import { p as A, h as B } from "./uid-BeWsLRS3.js";
2
+ function N(n) {
3
+ const a = Math.floor((Date.now() - n) / 1e3);
4
+ return a < 60 ? "just now" : a < 3600 ? `${Math.floor(a / 60)}m` : a < 86400 ? `${Math.floor(a / 3600)}h` : `${Math.floor(a / 86400)}d`;
5
+ }
6
+ function o(n, a, h) {
7
+ const c = document.createElement(n);
8
+ return a && (c.className = a), h !== void 0 && (c.textContent = h), c;
9
+ }
10
+ const _ = `
11
+ .ocl { --ocl-accent:#f5713c; --ocl-bg:#f3efe9; --ocl-card:#fff; --ocl-line:#ececec; --ocl-ink:#1c1b1a; --ocl-mut:#9b9690;
12
+ display:flex; flex-direction:column; height:100%; background:var(--ocl-bg);
13
+ font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif; color:var(--ocl-ink); overflow:hidden; }
14
+ .ocl-head { display:flex; align-items:center; padding:14px 16px 10px; background:var(--ocl-card); border-bottom:1px solid var(--ocl-line); }
15
+ .ocl-title { flex:1; font-size:18px; font-weight:700; }
16
+ .ocl-search-wrap { padding:8px 12px; background:var(--ocl-card); border-bottom:1px solid var(--ocl-line); }
17
+ .ocl-search { width:100%; box-sizing:border-box; border:none; background:var(--ocl-bg); border-radius:20px; padding:8px 14px; font:inherit; font-size:14px; outline:none; }
18
+ .ocl-body { flex:1; overflow-y:auto; }
19
+ .ocl-section { padding:6px 16px 4px; font-size:11px; font-weight:700; color:var(--ocl-mut); text-transform:uppercase; letter-spacing:.5px; background:var(--ocl-bg); }
20
+ .ocl-empty { padding:40px 20px; text-align:center; color:var(--ocl-mut); font-size:14px; }
21
+ .ocl-row { display:flex; align-items:center; gap:12px; padding:11px 16px; background:var(--ocl-card); border:none; width:100%; text-align:left; cursor:pointer; border-bottom:1px solid var(--ocl-line); transition:background .1s; }
22
+ .ocl-row:hover { background:#f7f5f2; }
23
+ .ocl-row.unread { background:var(--ocl-card); }
24
+ .ocl-av { width:46px; height:46px; border-radius:50%; background:var(--ocl-accent); color:#fff; font-size:18px; font-weight:700; display:flex; align-items:center; justify-content:center; flex:none; position:relative; }
25
+ .ocl-dot { position:absolute; bottom:1px; right:1px; width:12px; height:12px; border-radius:50%; border:2px solid var(--ocl-card); background:var(--ocl-mut); }
26
+ .ocl-dot.open { background:#22c55e; }
27
+ .ocl-dot.waiting { background:#f59e0b; }
28
+ .ocl-info { flex:1; min-width:0; }
29
+ .ocl-name { font-size:15px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-bottom:2px; }
30
+ .ocl-row.unread .ocl-name { font-weight:700; }
31
+ .ocl-preview { font-size:13px; color:var(--ocl-mut); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
32
+ .ocl-row.unread .ocl-preview { color:var(--ocl-ink); }
33
+ .ocl-right { display:flex; flex-direction:column; align-items:flex-end; gap:4px; flex:none; }
34
+ .ocl-time { font-size:11px; color:var(--ocl-mut); }
35
+ .ocl-row.unread .ocl-time { color:var(--ocl-accent); font-weight:600; }
36
+ .ocl-badge { background:var(--ocl-accent); color:#fff; border-radius:999px; font-size:11px; font-weight:700; min-width:20px; height:20px; padding:0 5px; display:flex; align-items:center; justify-content:center; }
37
+ .ocl-spinner { padding:24px; text-align:center; color:var(--ocl-mut); font-size:13px; }
38
+ @media (max-width:480px) { .ocl-row { padding:12px 14px; } .ocl-name { font-size:14px; } }
39
+ `;
40
+ function O(n) {
41
+ const a = n.userId ?? A(), h = B(n.url), c = n.i18n ?? {}, E = n.accent ?? "#f5713c";
42
+ if (!document.getElementById("ocl-styles")) {
43
+ const e = document.createElement("style");
44
+ e.id = "ocl-styles", e.textContent = _.replace(/#f5713c/g, E), document.head.append(e);
45
+ }
46
+ const w = o("div", "ocl"), b = o("div", "ocl-head");
47
+ b.append(o("span", "ocl-title", c.title ?? "Messages"));
48
+ const y = o("div", "ocl-search-wrap"), p = o("input", "ocl-search");
49
+ p.placeholder = c.search ?? "🔍 Search", p.type = "search", y.append(p);
50
+ const r = o("div", "ocl-body");
51
+ r.append(o("div", "ocl-spinner", "Loading…")), w.append(b, y, r), n.el.replaceChildren(w);
52
+ const k = `ocl_seen_${n.profileId}_${a.slice(-8)}`;
53
+ let u = {};
54
+ try {
55
+ u = JSON.parse(localStorage.getItem(k) ?? "{}");
56
+ } catch {
57
+ }
58
+ const U = () => {
59
+ try {
60
+ localStorage.setItem(k, JSON.stringify(u));
61
+ } catch {
62
+ }
63
+ };
64
+ let S = [], g = !1;
65
+ const j = async () => {
66
+ const e = await fetch(
67
+ `${h}/conversations/mine?profileId=${encodeURIComponent(n.profileId)}`,
68
+ { headers: { authorization: `Bearer ${a}` } }
69
+ );
70
+ return e.ok ? ((await e.json()).conversations ?? []).sort((l, s) => s.updatedAt - l.updatedAt) : [];
71
+ }, C = (e, i) => {
72
+ if (g) return;
73
+ const l = i ? e.filter(
74
+ (t) => (t.subjectTitle ?? "General enquiry").toLowerCase().includes(i) || (t.lastMessage ?? "").toLowerCase().includes(i)
75
+ ) : e;
76
+ if (r.replaceChildren(), !l.length) {
77
+ r.append(o("div", "ocl-empty", i ? "No results." : c.empty ?? "No conversations yet."));
78
+ return;
79
+ }
80
+ const s = (t) => (t.lastSeq ?? 0) > (u[t.id] ?? 0), d = l.filter(s), f = l.filter((t) => !s(t));
81
+ if (d.length) {
82
+ r.append(o("div", "ocl-section", `${c.unread ?? "Unread"} (${d.length})`));
83
+ for (const t of d) r.append(z(t, s(t)));
84
+ }
85
+ if (f.length) {
86
+ r.append(o("div", "ocl-section", d.length ? c.all ?? "All conversations" : ""));
87
+ for (const t of f) r.append(z(t, !1));
88
+ }
89
+ }, z = (e, i) => {
90
+ var I;
91
+ const l = e.subjectTitle ?? "General enquiry", s = ((I = l[0]) == null ? void 0 : I.toUpperCase()) ?? "?", d = e.lastSeq ?? 0, f = i ? Math.max(1, d - (u[e.id] ?? 0)) : 0, t = o("button", `ocl-row${i ? " unread" : ""}`), $ = o("div", "ocl-av", s), v = o("div", "ocl-dot");
92
+ e.state === "open" ? v.classList.add("open") : e.state === "awaiting_staff" && v.classList.add("waiting"), $.append(v), t.append($);
93
+ const m = o("div", "ocl-info");
94
+ m.append(o("div", "ocl-name", l));
95
+ const q = {
96
+ open: "Open",
97
+ awaiting_staff: "Waiting for reply…",
98
+ resolved: "Resolved ✓",
99
+ closed: "Closed"
100
+ };
101
+ m.append(o("div", "ocl-preview", e.lastMessage ?? q[e.state] ?? e.state)), t.append(m);
102
+ const x = o("div", "ocl-right");
103
+ return x.append(o("div", "ocl-time", N(e.updatedAt))), f > 0 && x.append(o("div", "ocl-badge", String(f > 99 ? "99+" : f))), t.append(x), t.addEventListener("click", () => {
104
+ var M;
105
+ d > 0 && (u[e.id] = d, U()), t.classList.remove("unread"), (M = x.querySelector(".ocl-badge")) == null || M.remove(), n.onSelect(e);
106
+ }), t;
107
+ }, L = () => {
108
+ g || j().then((e) => {
109
+ g || (S = e, C(e, p.value.trim().toLowerCase()));
110
+ }).catch(() => {
111
+ g || r.replaceChildren(o("div", "ocl-empty", c.error ?? "Could not load conversations."));
112
+ });
113
+ };
114
+ return p.addEventListener("input", () => C(S, p.value.trim().toLowerCase())), L(), {
115
+ refresh: L,
116
+ close() {
117
+ g = !0, n.el.replaceChildren();
118
+ }
119
+ };
120
+ }
121
+ export {
122
+ O as mountChatList
123
+ };
124
+ //# sourceMappingURL=chatlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chatlist.js","sources":["../src/chatlist.ts"],"sourcesContent":["/**\n * chatlist.ts — standalone chat list widget.\n *\n * Completely separate from mount() / the chat widget.\n * Shows all conversations for a given userId / guest on a profile.\n * Tapping a row fires onSelect(entry) — the caller decides what to do\n * (navigate to a new page, open a ChatWidget inline, etc.)\n *\n * Usage (vanilla):\n * import { mountChatList } from '@paramms/chat-widget/chatlist'\n * const handle = mountChatList({\n * el: document.getElementById('chat-list'),\n * url: 'wss://api.paramms.com/ws',\n * profileId: 'p_usedcars',\n * userId: currentUser.id, // optional — uses localStorage UID if omitted\n * onSelect: (entry) => {\n * window.location.href = `/listings/${entry.subjectId}#chat`\n * },\n * })\n * handle.refresh() // manually re-fetch the list\n * handle.close() // unmount and clean up\n */\n\nimport { httpBaseFromWsUrl } from './history.js'\nimport { persistentUid } from './uid.js'\n\nexport interface ChatListEntry {\n id: string\n subjectId?: string\n subjectTitle?: string\n state: string\n updatedAt: number\n lastSeq?: number\n lastMessage?: string\n}\n\nexport interface ChatListOptions {\n /** Mount target element */\n el: HTMLElement\n /** Relay WebSocket URL — e.g. wss://api.paramms.com/ws */\n url: string\n /** Profile ID to scope conversations to */\n profileId: string\n /** Your logged-in user's stable ID. Omit for anonymous (uses localStorage UID) */\n userId?: string\n /** Called when the user taps a conversation row */\n onSelect: (entry: ChatListEntry) => void\n /** Brand colour hex — default '#f5713c' */\n accent?: string\n /** i18n overrides */\n i18n?: {\n title?: string // default 'Messages'\n search?: string // default '🔍 Search'\n empty?: string // default 'No conversations yet.'\n unread?: string // default 'Unread'\n all?: string // default 'All conversations'\n error?: string // default 'Could not load conversations.'\n }\n}\n\nexport interface ChatListHandle {\n /** Re-fetch and re-render the list */\n refresh(): void\n /** Unmount and clean up */\n close(): void\n}\n\nfunction timeAgo(ts: number): string {\n const s = Math.floor((Date.now() - ts) / 1000)\n if (s < 60) return 'just now'\n if (s < 3600) return `${Math.floor(s / 60)}m`\n if (s < 86400) return `${Math.floor(s / 3600)}h`\n return `${Math.floor(s / 86400)}d`\n}\n\nfunction el(tag: string, cls?: string, text?: string): HTMLElement {\n const e = document.createElement(tag)\n if (cls) e.className = cls\n if (text !== undefined) e.textContent = text\n return e\n}\n\nconst CSS = `\n.ocl { --ocl-accent:#f5713c; --ocl-bg:#f3efe9; --ocl-card:#fff; --ocl-line:#ececec; --ocl-ink:#1c1b1a; --ocl-mut:#9b9690;\n display:flex; flex-direction:column; height:100%; background:var(--ocl-bg);\n font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif; color:var(--ocl-ink); overflow:hidden; }\n.ocl-head { display:flex; align-items:center; padding:14px 16px 10px; background:var(--ocl-card); border-bottom:1px solid var(--ocl-line); }\n.ocl-title { flex:1; font-size:18px; font-weight:700; }\n.ocl-search-wrap { padding:8px 12px; background:var(--ocl-card); border-bottom:1px solid var(--ocl-line); }\n.ocl-search { width:100%; box-sizing:border-box; border:none; background:var(--ocl-bg); border-radius:20px; padding:8px 14px; font:inherit; font-size:14px; outline:none; }\n.ocl-body { flex:1; overflow-y:auto; }\n.ocl-section { padding:6px 16px 4px; font-size:11px; font-weight:700; color:var(--ocl-mut); text-transform:uppercase; letter-spacing:.5px; background:var(--ocl-bg); }\n.ocl-empty { padding:40px 20px; text-align:center; color:var(--ocl-mut); font-size:14px; }\n.ocl-row { display:flex; align-items:center; gap:12px; padding:11px 16px; background:var(--ocl-card); border:none; width:100%; text-align:left; cursor:pointer; border-bottom:1px solid var(--ocl-line); transition:background .1s; }\n.ocl-row:hover { background:#f7f5f2; }\n.ocl-row.unread { background:var(--ocl-card); }\n.ocl-av { width:46px; height:46px; border-radius:50%; background:var(--ocl-accent); color:#fff; font-size:18px; font-weight:700; display:flex; align-items:center; justify-content:center; flex:none; position:relative; }\n.ocl-dot { position:absolute; bottom:1px; right:1px; width:12px; height:12px; border-radius:50%; border:2px solid var(--ocl-card); background:var(--ocl-mut); }\n.ocl-dot.open { background:#22c55e; }\n.ocl-dot.waiting { background:#f59e0b; }\n.ocl-info { flex:1; min-width:0; }\n.ocl-name { font-size:15px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-bottom:2px; }\n.ocl-row.unread .ocl-name { font-weight:700; }\n.ocl-preview { font-size:13px; color:var(--ocl-mut); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.ocl-row.unread .ocl-preview { color:var(--ocl-ink); }\n.ocl-right { display:flex; flex-direction:column; align-items:flex-end; gap:4px; flex:none; }\n.ocl-time { font-size:11px; color:var(--ocl-mut); }\n.ocl-row.unread .ocl-time { color:var(--ocl-accent); font-weight:600; }\n.ocl-badge { background:var(--ocl-accent); color:#fff; border-radius:999px; font-size:11px; font-weight:700; min-width:20px; height:20px; padding:0 5px; display:flex; align-items:center; justify-content:center; }\n.ocl-spinner { padding:24px; text-align:center; color:var(--ocl-mut); font-size:13px; }\n@media (max-width:480px) { .ocl-row { padding:12px 14px; } .ocl-name { font-size:14px; } }\n`\n\n/** Mount a standalone chat list widget. */\nexport function mountChatList(opts: ChatListOptions): ChatListHandle {\n const token = opts.userId ?? persistentUid()\n const httpBase = httpBaseFromWsUrl(opts.url)\n const i18n = opts.i18n ?? {}\n const accent = opts.accent ?? '#f5713c'\n\n // Inject CSS once\n if (!document.getElementById('ocl-styles')) {\n const s = document.createElement('style'); s.id = 'ocl-styles'\n s.textContent = CSS.replace(/#f5713c/g, accent)\n document.head.append(s)\n }\n\n // Build DOM\n const root = el('div', 'ocl')\n const head = el('div', 'ocl-head')\n head.append(el('span', 'ocl-title', i18n.title ?? 'Messages'))\n\n const searchWrap = el('div', 'ocl-search-wrap')\n const searchIn = el('input', 'ocl-search') as HTMLInputElement\n searchIn.placeholder = i18n.search ?? '🔍 Search'; searchIn.type = 'search'\n searchWrap.append(searchIn)\n\n const body = el('div', 'ocl-body')\n body.append(el('div', 'ocl-spinner', 'Loading…'))\n root.append(head, searchWrap, body)\n opts.el.replaceChildren(root)\n\n // Track seen seqs for unread counts (persisted in localStorage)\n const seenKey = `ocl_seen_${opts.profileId}_${token.slice(-8)}`\n let seenSeq: Record<string, number> = {}\n try { seenSeq = JSON.parse(localStorage.getItem(seenKey) ?? '{}') } catch {}\n\n const saveSeenSeq = () => {\n try { localStorage.setItem(seenKey, JSON.stringify(seenSeq)) } catch {}\n }\n\n let allEntries: ChatListEntry[] = []\n let destroyed = false\n\n // Fetch conversations from server\n const fetchEntries = async (): Promise<ChatListEntry[]> => {\n const res = await fetch(\n `${httpBase}/conversations/mine?profileId=${encodeURIComponent(opts.profileId)}`,\n { headers: { authorization: `Bearer ${token}` } },\n )\n if (!res.ok) return []\n const data = await res.json() as { conversations?: ChatListEntry[] }\n return (data.conversations ?? []).sort((a, b) => b.updatedAt - a.updatedAt)\n }\n\n // Render rows from entries, optionally filtered by search query\n const renderRows = (entries: ChatListEntry[], query: string) => {\n if (destroyed) return\n const filtered = query\n ? entries.filter(e =>\n (e.subjectTitle ?? 'General enquiry').toLowerCase().includes(query) ||\n (e.lastMessage ?? '').toLowerCase().includes(query)\n )\n : entries\n\n body.replaceChildren()\n\n if (!filtered.length) {\n body.append(el('div', 'ocl-empty', query ? 'No results.' : (i18n.empty ?? 'No conversations yet.')))\n return\n }\n\n const isUnread = (e: ChatListEntry) =>\n (e.lastSeq ?? 0) > (seenSeq[e.id] ?? 0)\n\n const unread = filtered.filter(isUnread)\n const read = filtered.filter(e => !isUnread(e))\n\n if (unread.length) {\n body.append(el('div', 'ocl-section', `${i18n.unread ?? 'Unread'} (${unread.length})`))\n for (const e of unread) body.append(buildRow(e, isUnread(e)))\n }\n if (read.length) {\n body.append(el('div', 'ocl-section', unread.length ? (i18n.all ?? 'All conversations') : ''))\n for (const e of read) body.append(buildRow(e, false))\n }\n }\n\n const buildRow = (entry: ChatListEntry, unread: boolean): HTMLElement => {\n const name = entry.subjectTitle ?? 'General enquiry'\n const initial = name[0]?.toUpperCase() ?? '?'\n const lastSeq = entry.lastSeq ?? 0\n const unreadCount = unread ? Math.max(1, lastSeq - (seenSeq[entry.id] ?? 0)) : 0\n\n const row = el('button', `ocl-row${unread ? ' unread' : ''}`) as HTMLButtonElement\n\n // Avatar\n const av = el('div', 'ocl-av', initial)\n const dot = el('div', 'ocl-dot')\n if (entry.state === 'open') dot.classList.add('open')\n else if (entry.state === 'awaiting_staff') dot.classList.add('waiting')\n av.append(dot)\n row.append(av)\n\n // Info\n const info = el('div', 'ocl-info')\n info.append(el('div', 'ocl-name', name))\n const stateMap: Record<string, string> = {\n open: 'Open', awaiting_staff: 'Waiting for reply…',\n resolved: 'Resolved ✓', closed: 'Closed',\n }\n info.append(el('div', 'ocl-preview', entry.lastMessage ?? stateMap[entry.state] ?? entry.state))\n row.append(info)\n\n // Right\n const right = el('div', 'ocl-right')\n right.append(el('div', 'ocl-time', timeAgo(entry.updatedAt)))\n if (unreadCount > 0) {\n right.append(el('div', 'ocl-badge', String(unreadCount > 99 ? '99+' : unreadCount)))\n }\n row.append(right)\n\n row.addEventListener('click', () => {\n // Mark as read\n if (lastSeq > 0) { seenSeq[entry.id] = lastSeq; saveSeenSeq() }\n row.classList.remove('unread')\n right.querySelector('.ocl-badge')?.remove()\n opts.onSelect(entry)\n })\n\n return row\n }\n\n const refresh = () => {\n if (destroyed) return\n fetchEntries().then(entries => {\n if (destroyed) return\n allEntries = entries\n renderRows(entries, searchIn.value.trim().toLowerCase())\n }).catch(() => {\n if (destroyed) return\n body.replaceChildren(el('div', 'ocl-empty', i18n.error ?? 'Could not load conversations.'))\n })\n }\n\n searchIn.addEventListener('input', () => renderRows(allEntries, searchIn.value.trim().toLowerCase()))\n\n // Initial fetch\n refresh()\n\n return {\n refresh,\n close() {\n destroyed = true\n opts.el.replaceChildren()\n },\n }\n}\n"],"names":["timeAgo","ts","s","el","tag","cls","text","e","CSS","mountChatList","opts","token","persistentUid","httpBase","httpBaseFromWsUrl","i18n","accent","root","head","searchWrap","searchIn","body","seenKey","seenSeq","saveSeenSeq","allEntries","destroyed","fetchEntries","res","a","b","renderRows","entries","query","filtered","isUnread","unread","read","buildRow","entry","name","initial","_a","lastSeq","unreadCount","row","av","dot","info","stateMap","right","refresh"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -28,11 +28,6 @@ export interface MountOptions {
28
28
  launcher?: boolean;
29
29
  /** Position of the launcher button: default 'bottom-right' */
30
30
  position?: 'bottom-right' | 'bottom-left';
31
- /** If true, shows a 💬 button in the header that opens a list of the
32
- * guest's other conversations (e.g. a marketplace where each item gets
33
- * its own subjectId/thread) and lets them switch between them.
34
- * Off by default — single-conversation embeds don't need this. */
35
- showChatList?: boolean;
36
31
  /** Optional user info for identified users. When provided, the name/email/
37
32
  * avatar are shown to agents in the dashboard instead of the anonymous ID.
38
33
  * The token still controls identity — this is display metadata only.
@@ -53,7 +48,7 @@ export interface WidgetHandle {
53
48
  export declare function mount(opts: MountOptions): WidgetHandle;
54
49
  export { ChatStore } from './store.js';
55
50
  export { ConnectionManager } from './connection.js';
56
- export { Renderer, type ChatListEntry } from './renderer.js';
51
+ export { Renderer } from './renderer.js';
57
52
  export { asConversationId };
58
53
  export { E2ESession, extractX3DHInit, type X3DHBundle } from './e2e.js';
59
54
  export { PersistentOutbox, type OutboxItem } from './outbox.js';