@banbox/chat 1.0.8 → 1.0.10

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 (43) hide show
  1. package/dist/index.cjs +1203 -265
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +18 -2
  4. package/dist/index.d.ts +18 -2
  5. package/dist/index.js +1127 -190
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/chat/InboxPopup.tsx +38 -35
  9. package/src/chat/SinglePopup.tsx +81 -40
  10. package/src/icons/index.tsx +55 -0
  11. package/src/index.ts +14 -12
  12. package/src/modals/ChatAddressModal.tsx +844 -0
  13. package/src/modals/{chat/ChatConfirmModal.tsx → ChatConfirmModal.tsx} +2 -2
  14. package/src/modals/ChatTranslateSettingsModal.tsx +182 -0
  15. package/src/styles/index.build.css +15 -0
  16. package/src/styles/index.css +10 -2
  17. package/src/ui/{chat/AttachmentPreviewStrip.tsx → AttachmentPreviewStrip.tsx} +2 -2
  18. package/src/ui/{chat/ChatComposerBar.tsx → ChatComposerBar.tsx} +2 -2
  19. package/src/ui/{chat/ChatFooter.tsx → ChatFooter.tsx} +102 -8
  20. package/src/ui/{chat/ChatIdentity.tsx → ChatIdentity.tsx} +2 -2
  21. package/src/ui/{chat/ChatInquiryBar.tsx → ChatInquiryBar.tsx} +1 -1
  22. package/src/ui/ChatKebabMenu.tsx +125 -0
  23. package/src/ui/{chat/ChatListHeader.tsx → ChatListHeader.tsx} +1 -1
  24. package/src/ui/{chat/ChatMessageItem.tsx → ChatMessageItem.tsx} +10 -32
  25. package/src/ui/{chat/ChatScroll.tsx → ChatScroll.tsx} +1 -1
  26. package/src/ui/{chat/ChatSpinner.tsx → ChatSpinner.tsx} +1 -1
  27. package/src/ui/{chat/ChatThreadItem.tsx → ChatThreadItem.tsx} +1 -1
  28. package/src/ui/{chat/MessageHoverActions.tsx → MessageHoverActions.tsx} +2 -2
  29. package/src/ui/{chat/ReplyCard.tsx → ReplyCard.tsx} +2 -2
  30. package/src/ui/{chat/TypingIndicator.tsx → TypingIndicator.tsx} +1 -1
  31. package/src/ui/{chat/drop-up → drop-up}/BusinessCardDropup.tsx +15 -3
  32. package/src/ui/{chat/drop-up → drop-up}/EmojiDropup.tsx +1 -1
  33. package/src/ui/{chat/message-items → message-items}/ChatAddressCard.tsx +4 -4
  34. package/src/ui/{chat/message-items → message-items}/ChatBubbleFiles.tsx +1 -1
  35. package/src/ui/{chat/message-items → message-items}/ChatBubbleImages.tsx +2 -2
  36. package/src/ui/{chat/message-items → message-items}/ChatBusinessCard.tsx +1 -1
  37. package/src/ui/{chat/scrollToMessage.ts → scrollToMessage.ts} +1 -1
  38. package/src/ui/{chat/types.ts → types.ts} +2 -2
  39. package/src/utils/theme.ts +37 -0
  40. package/src/modals/chat/ChatTranslateSettingsModal.tsx +0 -180
  41. /package/src/ui/{chat/ChatHeader.tsx → ChatHeader.tsx} +0 -0
  42. /package/src/ui/{chat/message-items → message-items}/ChatBubbleAudio.tsx +0 -0
  43. /package/src/ui/{chat/message-items → message-items}/ChatBubbleText.tsx +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@banbox/chat",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Banbox Chat UI components — reusable across all Banbox React/Next.js projects",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -6,19 +6,21 @@ import React, { useCallback, useEffect, useRef, useState } from "react";
6
6
 
7
7
  import { useChatUI } from "../contexts/ChatUIContext";
8
8
  import { useGallery } from "../contexts/GalleryContext";
9
- import ChatConfirmModal from "../modals/chat/ChatConfirmModal";
10
- import ChatFooter from "../ui/chat/ChatFooter";
11
- import ChatHeader from "../ui/chat/ChatHeader";
12
- import ChatIdentity from "../ui/chat/ChatIdentity";
13
- import ChatInquiryBar from "../ui/chat/ChatInquiryBar";
14
- import ChatListHeader from "../ui/chat/ChatListHeader";
15
- import ChatMessageItem from "../ui/chat/ChatMessageItem";
16
- import ChatScroll from "../ui/chat/ChatScroll";
17
- import type { ChatThreadStatus } from "../ui/chat/ChatThreadItem";
18
- import ChatThreadItem from "../ui/chat/ChatThreadItem";
19
- import TypingIndicator from "../ui/chat/TypingIndicator";
9
+ import ChatConfirmModal from "../modals/ChatConfirmModal";
10
+ import ChatFooter from "../ui/ChatFooter";
11
+ import ChatHeader from "../ui/ChatHeader";
12
+ import ChatIdentity from "../ui/ChatIdentity";
13
+ import ChatInquiryBar from "../ui/ChatInquiryBar";
14
+ import ChatListHeader from "../ui/ChatListHeader";
15
+ import ChatMessageItem from "../ui/ChatMessageItem";
16
+ import ChatScroll from "../ui/ChatScroll";
17
+ import type { ChatThreadStatus } from "../ui/ChatThreadItem";
18
+ import ChatThreadItem from "../ui/ChatThreadItem";
19
+ import TypingIndicator from "../ui/TypingIndicator";
20
20
  import ChatImagePreviewModal from "./ChatImagePreviewModal";
21
+ import { GRADIENT_BORDER, getThemeAttr, getThemeVars } from "../utils/theme";
21
22
 
23
+ import ChatKebabMenu from "../ui/ChatKebabMenu";
22
24
  import type { ChatAdapter, ChatUICallbacks } from "../adapter/types";
23
25
  import type { Message, MessageRef, Thread } from "../types";
24
26
 
@@ -43,23 +45,7 @@ const avatarBgByInitial: Record<string, string> = {
43
45
  b: "#F0EDEB",
44
46
  };
45
47
 
46
- const GRADIENT_BORDER =
47
- "linear-gradient(236.83deg, rgba(51,201,212,0.3) 0.4%, rgba(39,83,251,0.3) 30.28%, rgba(39,83,251,0.3) 50.2%, rgba(39,83,251,0.3) 65.14%, rgba(235,67,255,0.3) 100%)";
48
48
 
49
- function getThemeAttr(theme?: ChatTheme): string {
50
- if (!theme || theme === "marketplace") return "marketplace";
51
- if (theme === "admin") return "admin";
52
- return "custom";
53
- }
54
-
55
- function getThemeVars(theme?: ChatTheme): React.CSSProperties {
56
- if (!theme || theme === "marketplace" || theme === "admin") return {};
57
- const vars: Record<string, string> = {};
58
- if (theme.primary) vars["--color-banbox-primary"] = theme.primary;
59
- if (theme.primaryActive) vars["--color-banbox-primary-active"] = theme.primaryActive;
60
- if (theme.surfaceLow) vars["--color-banbox-surface-container-low"] = theme.surfaceLow;
61
- return vars as React.CSSProperties;
62
- }
63
49
 
64
50
  /* ══════════════════════════════════════════════════
65
51
  Component
@@ -135,12 +121,19 @@ const InboxPopup: React.FC<InboxPopupProps> = ({ adapter, uiCallbacks, theme })
135
121
 
136
122
  const prevActiveIdRef = useRef(activeId);
137
123
  useEffect(() => {
124
+ // Mark read on thread SWITCH
138
125
  if (prevActiveIdRef.current !== activeId) {
139
126
  prevActiveIdRef.current = activeId;
140
127
  if (activeId) adapter.threads.markRead?.(activeId);
141
128
  }
142
129
  }, [activeId, adapter]);
143
130
 
131
+ // Mark read on initial open (prevActiveIdRef starts equal to activeId so the above won't fire)
132
+ useEffect(() => {
133
+ if (activeId) adapter.threads.markRead?.(activeId);
134
+ // eslint-disable-next-line react-hooks/exhaustive-deps
135
+ }, []);
136
+
144
137
  const toRef = (m: Message): MessageRef => ({
145
138
  id: m.id,
146
139
  author: typeof m.author === "string" ? m.author : "U",
@@ -183,7 +176,7 @@ const InboxPopup: React.FC<InboxPopupProps> = ({ adapter, uiCallbacks, theme })
183
176
  RENDER
184
177
  ══════════════════════════════════════════════════ */
185
178
  return (
186
- <div className="fixed bottom-4 right-4 z-[10002]">
179
+ <div className="fixed bottom-4 right-4 z-10002">
187
180
  {/* Backdrop */}
188
181
  <motion.button
189
182
  aria-label="Close chat"
@@ -255,13 +248,23 @@ const InboxPopup: React.FC<InboxPopupProps> = ({ adapter, uiCallbacks, theme })
255
248
  )
256
249
  }
257
250
  right={
258
- uiCallbacks?.renderKebabMenu?.({
259
- pinned: Boolean(activeThread?.pinned),
260
- onPinToggle: () => {
261
- if (activeId) adapter.threads.pin(activeId, !activeThread?.pinned);
262
- },
263
- onDelete: () => setShowDelete(true),
264
- }) ?? null
251
+ uiCallbacks?.renderKebabMenu
252
+ ? uiCallbacks.renderKebabMenu({
253
+ pinned: Boolean(activeThread?.pinned),
254
+ onPinToggle: () => {
255
+ if (activeId) adapter.threads.pin(activeId, !activeThread?.pinned);
256
+ },
257
+ onDelete: () => setShowDelete(true),
258
+ })
259
+ : (
260
+ <ChatKebabMenu
261
+ pinned={Boolean(activeThread?.pinned)}
262
+ onPinToggle={() => {
263
+ if (activeId) adapter.threads.pin(activeId, !activeThread?.pinned);
264
+ }}
265
+ onDelete={() => setShowDelete(true)}
266
+ />
267
+ )
265
268
  }
266
269
  />
267
270
  </div>
@@ -5,32 +5,35 @@ import { motion } from "framer-motion";
5
5
  import React from "react";
6
6
 
7
7
  import { useChatUI } from "../contexts/ChatUIContext";
8
+ import { useGallery } from "../contexts/GalleryContext";
8
9
  import { ChatXIcon } from "../icons";
9
- import ChatFooter from "../ui/chat/ChatFooter";
10
- import ChatHeader from "../ui/chat/ChatHeader";
11
- import ChatIdentity from "../ui/chat/ChatIdentity";
12
- import ChatMessageItem from "../ui/chat/ChatMessageItem";
13
- import ChatScroll from "../ui/chat/ChatScroll";
14
- import TypingIndicator from "../ui/chat/TypingIndicator";
10
+ import ChatKebabMenu from "../ui/ChatKebabMenu";
11
+ import ChatConfirmModal from "../modals/ChatConfirmModal";
12
+ import ChatFooter from "../ui/ChatFooter";
13
+ import ChatHeader from "../ui/ChatHeader";
14
+ import ChatIdentity from "../ui/ChatIdentity";
15
+ import ChatMessageItem from "../ui/ChatMessageItem";
16
+ import ChatScroll from "../ui/ChatScroll";
17
+ import TypingIndicator from "../ui/TypingIndicator";
18
+ import ChatImagePreviewModal from "./ChatImagePreviewModal";
19
+ import { GRADIENT_BORDER, getThemeAttr, getThemeVars } from "../utils/theme";
15
20
 
16
21
  import type { ChatAdapter, ChatUICallbacks } from "../adapter/types";
17
22
  import type { Message, MessageRef, Reference, Thread } from "../types";
18
23
  import type { ChatTheme } from "./InboxPopup";
19
24
 
20
- /* ─── Helpers ─── */
21
- const GRADIENT_BORDER =
22
- "linear-gradient(236.83deg, rgba(51,201,212,0.3) 0.4%, rgba(39,83,251,0.3) 30.28%, rgba(39,83,251,0.3) 50.2%, rgba(39,83,251,0.3) 65.14%, rgba(235,67,255,0.3) 100%)";
25
+
23
26
 
24
27
  function coalesceThreadId(reference: Reference | undefined, threads: Thread[]): string {
25
- const referenceId = reference?.id;
26
- if (reference?.kind === "quotation") {
27
- return threads.find((t) => t.id === "t4")?.id ?? (threads[0]?.id ?? "");
28
- }
28
+ if (!reference?.id) return threads[0]?.id ?? "";
29
+ const refId = reference.id;
30
+ // Priority: exact thread.id match orderId match inquiryId match → first thread
29
31
  return (
30
- (referenceId &&
31
- (threads.find((t) => t.id === referenceId)?.id ||
32
- threads.find((t) => t.inquiryId === referenceId)?.id)) ||
33
- (threads.length ? threads[0].id : "")
32
+ threads.find((t) => t.id === refId)?.id ??
33
+ threads.find((t) => t.orderId === refId)?.id ??
34
+ threads.find((t) => t.inquiryId === refId)?.id ??
35
+ threads[0]?.id ??
36
+ ""
34
37
  );
35
38
  }
36
39
 
@@ -46,20 +49,7 @@ function toRef(m: Message): MessageRef {
46
49
  };
47
50
  }
48
51
 
49
- function getThemeAttr(theme?: ChatTheme): string {
50
- if (!theme || theme === "marketplace") return "marketplace";
51
- if (theme === "admin") return "admin";
52
- return "custom";
53
- }
54
52
 
55
- function getThemeVars(theme?: ChatTheme): React.CSSProperties {
56
- if (!theme || theme === "marketplace" || theme === "admin") return {};
57
- const vars: Record<string, string> = {};
58
- if (theme.primary) vars["--color-banbox-primary"] = theme.primary;
59
- if (theme.primaryActive) vars["--color-banbox-primary-active"] = theme.primaryActive;
60
- if (theme.surfaceLow) vars["--color-banbox-surface-container-low"] = theme.surfaceLow;
61
- return vars as React.CSSProperties;
62
- }
63
53
 
64
54
  export type SinglePopupProps = {
65
55
  adapter: ChatAdapter;
@@ -72,10 +62,21 @@ export type SinglePopupProps = {
72
62
  ══════════════════════════════════════════════════ */
73
63
  const SinglePopup: React.FC<SinglePopupProps> = ({ adapter, uiCallbacks, theme }) => {
74
64
  const { close, reference } = useChatUI();
65
+ const { isOpen: isGalleryOpen, closeGallery } = useGallery();
66
+
67
+ // ── Threads — subscribed so real-API updates (new msg, pin, delete) are reflected
68
+ const [threads, setThreads] = React.useState<Thread[]>(() => adapter.threads.list(reference));
69
+ React.useEffect(() => {
70
+ // Refresh once on mount (covers any gap between render and subscribe)
71
+ setThreads(adapter.threads.list(reference));
72
+ const unsub = adapter.threads.subscribe(() => {
73
+ setThreads(adapter.threads.list(reference));
74
+ });
75
+ return unsub;
76
+ }, [adapter, reference]);
75
77
 
76
- const threads = adapter.threads.list(reference);
77
78
  const initialThreadId = React.useMemo(
78
- () => coalesceThreadId(reference, threads),
79
+ () => coalesceThreadId(reference, adapter.threads.list(reference)),
79
80
  // eslint-disable-next-line react-hooks/exhaustive-deps
80
81
  [reference],
81
82
  );
@@ -101,6 +102,7 @@ const SinglePopup: React.FC<SinglePopupProps> = ({ adapter, uiCallbacks, theme }
101
102
  );
102
103
  const [scrollKey, setScrollKey] = React.useState<number>(Date.now());
103
104
  const [replyTo, setReplyTo] = React.useState<MessageRef | undefined>(undefined);
105
+ const [showDelete, setShowDelete] = React.useState(false);
104
106
 
105
107
  React.useEffect(() => {
106
108
  if (!activeId || !adapter.messages.subscribe) return;
@@ -117,7 +119,17 @@ const SinglePopup: React.FC<SinglePopupProps> = ({ adapter, uiCallbacks, theme }
117
119
  setReplyTo(undefined);
118
120
  }, [activeId, adapter]);
119
121
 
120
- void uiCallbacks;
122
+ const handleConfirmDelete = React.useCallback(() => {
123
+ if (!activeId) { setShowDelete(false); return; }
124
+ adapter.threads.delete(activeId);
125
+ uiCallbacks?.showToast?.({
126
+ type: "success",
127
+ title: "Chat Deleted",
128
+ message: "The chat has been deleted successfully.",
129
+ });
130
+ setShowDelete(false);
131
+ close();
132
+ }, [activeId, adapter, uiCallbacks, close]);
121
133
 
122
134
  return (
123
135
  <div className="fixed bottom-4 right-4 z-[10002]">
@@ -169,13 +181,33 @@ const SinglePopup: React.FC<SinglePopupProps> = ({ adapter, uiCallbacks, theme }
169
181
  />
170
182
  }
171
183
  right={
172
- <button
173
- type="button"
174
- onClick={close}
175
- className="flex h-[34px] w-[34px] items-center justify-center rounded-full bg-white text-black shadow-[0px_2px_4px_0px_#A5A3AE4D] hover:bg-black/5 hover:text-[var(--color-banbox-warning)] cursor-pointer border-none"
176
- >
177
- <ChatXIcon className="h-6 w-6" />
178
- </button>
184
+ <div className="flex items-center gap-1">
185
+ {uiCallbacks?.renderKebabMenu
186
+ ? uiCallbacks.renderKebabMenu({
187
+ pinned: Boolean(activeThread?.pinned),
188
+ onPinToggle: () => {
189
+ if (activeId) adapter.threads.pin(activeId, !activeThread?.pinned);
190
+ },
191
+ onDelete: () => setShowDelete(true),
192
+ })
193
+ : (
194
+ <ChatKebabMenu
195
+ pinned={Boolean(activeThread?.pinned)}
196
+ onPinToggle={() => {
197
+ if (activeId) adapter.threads.pin(activeId, !activeThread?.pinned);
198
+ }}
199
+ onDelete={() => setShowDelete(true)}
200
+ />
201
+ )
202
+ }
203
+ <button
204
+ type="button"
205
+ onClick={close}
206
+ className="flex h-[34px] w-[34px] items-center justify-center rounded-full bg-white text-black shadow-[0px_2px_4px_0px_#A5A3AE4D] hover:bg-black/5 hover:text-[var(--color-banbox-warning)] cursor-pointer border-none"
207
+ >
208
+ <ChatXIcon className="h-6 w-6" />
209
+ </button>
210
+ </div>
179
211
  }
180
212
  />
181
213
  </div>
@@ -233,6 +265,15 @@ const SinglePopup: React.FC<SinglePopupProps> = ({ adapter, uiCallbacks, theme }
233
265
  </div>
234
266
  </div>
235
267
  </motion.div>
268
+
269
+ {/* Delete confirm modal */}
270
+ <ChatConfirmModal
271
+ open={showDelete}
272
+ onClose={() => setShowDelete(false)}
273
+ onConfirm={handleConfirmDelete}
274
+ />
275
+ {/* Image gallery preview */}
276
+ <ChatImagePreviewModal isOpen={isGalleryOpen} onClose={closeGallery} />
236
277
  </div>
237
278
  );
238
279
  };
@@ -212,6 +212,20 @@ export const MapPinIcon = ({ className = "" }: IconProps) => (
212
212
  </svg>
213
213
  );
214
214
 
215
+ export const MapIcon2 = ({ className = "" }: IconProps) => (
216
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
217
+ <path d="M7.9987 1.33203C5.41203 1.33203 3.33203 3.41203 3.33203 5.9987C3.33203 9.4987 7.9987 14.6654 7.9987 14.6654C7.9987 14.6654 12.6654 9.4987 12.6654 5.9987C12.6654 3.41203 10.5854 1.33203 7.9987 1.33203Z" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
218
+ <circle cx="8" cy="6" r="1.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
219
+ </svg>
220
+ );
221
+
222
+ export const FlyIcon = ({ className = "" }: IconProps) => (
223
+ <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
224
+ <path d="M16.5 1.5L8.25 9.75" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
225
+ <path d="M16.5 1.5L11.25 16.5L8.25 9.75L1.5 6.75L16.5 1.5Z" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
226
+ </svg>
227
+ );
228
+
215
229
  export const MenuIcon = ({ className }: IconProps) => (
216
230
  <svg width="24" height="24" className={className} viewBox="0 0 24 24" fill="currentColor">
217
231
  <circle cx="12" cy="5" r="2" />
@@ -246,3 +260,44 @@ export const ChatTrashIcon = ({ className }: IconProps) => (
246
260
  <path d="M7.5 5.83333V3.33333C7.5 2.8731 7.8731 2.5 8.33333 2.5H11.6667C12.1269 2.5 12.5 2.8731 12.5 3.33333V5.83333" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" />
247
261
  </svg>
248
262
  );
263
+
264
+ export const EditIcon = ({ className = "" }: IconProps) => (
265
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
266
+ <path d="M9 7H6C4.89543 7 4 7.89543 4 9V18C4 19.1046 4.89543 20 6 20H15C16.1046 20 17 19.1046 17 18V15" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" />
267
+ <path d="M9 15H12L20.5 6.49998C21.3284 5.67156 21.3284 4.32841 20.5 3.49998C19.6716 2.67156 18.3284 2.67156 17.5 3.49998L9 12V15" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" />
268
+ <path d="M16 5L19 8" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" />
269
+ </svg>
270
+ );
271
+
272
+ export const TrashIcon = ({ className }: IconProps) => (
273
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
274
+ <path d="M3.3335 5.83464H16.6668" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
275
+ <path d="M8.33317 9.16797V14.168" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
276
+ <path d="M11.6667 9.16797V14.168" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
277
+ <path d="M4.1665 5.83203L4.99984 15.832C4.99984 16.7525 5.74603 17.4987 6.6665 17.4987H13.3332C14.2536 17.4987 14.9998 16.7525 14.9998 15.832L15.8332 5.83203" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
278
+ <path d="M7.5 5.83333V3.33333C7.5 2.8731 7.8731 2.5 8.33333 2.5H11.6667C12.1269 2.5 12.5 2.8731 12.5 3.33333V5.83333" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
279
+ </svg>
280
+ );
281
+
282
+ export const EmailIcon = ({ className = "" }: IconProps) => (
283
+ <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
284
+ <path d="M3 3H15C15.825 3 16.5 3.675 16.5 4.5V13.5C16.5 14.325 15.825 15 15 15H3C2.175 15 1.5 14.325 1.5 13.5V4.5C1.5 3.675 2.175 3 3 3Z" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
285
+ <path d="M16.5 4.5L9 9.75L1.5 4.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
286
+ </svg>
287
+ );
288
+
289
+ export const BadgeHomeAddrIcon = ({ className = "" }: IconProps) => (
290
+ <svg width="12" height="12" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
291
+ <path d="M2.91667 7H1.75L7 1.75L12.25 7H11.0833" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
292
+ <path d="M2.91406 7V11.0833C2.91406 11.7277 3.4364 12.25 4.08073 12.25H9.91406C10.5584 12.25 11.0807 11.7277 11.0807 11.0833V7" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
293
+ <rect x="5.83594" y="7" width="2.33333" height="2.33333" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
294
+ </svg>
295
+ );
296
+
297
+ export const CheckboxFilledIcon = ({ className = "" }: IconProps) => (
298
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
299
+ <rect width="16" height="16" rx="4" fill="currentColor" />
300
+ <path d="M14.8161 1C13.1423 2.42824 11.7356 4.37456 10.6806 6.51692C9.68193 8.56126 8.99268 10.8016 8.69729 13H4.81498V12.972L3.12701 8.56126L2.4659 6.83897L2.18457 6.09685L3.83033 6.05484C4.26639 6.05484 4.66025 6.30688 4.75871 6.68495L5.72929 8.63127L6.517 10.1995L6.728 10.6196C6.91086 10.2415 7.09372 9.87748 7.29065 9.51342C8.34563 7.49708 9.49907 5.67678 10.8635 4.13652C11.6512 3.25438 12.5093 2.45624 13.4658 1.77013C13.8456 1.50408 14.2254 1.25204 14.6333 1.014H14.8161V1Z" fill="white" />
301
+ </svg>
302
+ );
303
+
package/src/index.ts CHANGED
@@ -39,18 +39,20 @@ export { ChatUIContext } from "./contexts/ChatUIContext";
39
39
  export type { ChatUIState, ChatVariant } from "./contexts/ChatUIContext";
40
40
 
41
41
  // ── Individual UI components (advanced usage / custom layouts) ────────────────
42
- export { default as ChatFooter } from "./ui/chat/ChatFooter";
43
- export { default as ChatHeader } from "./ui/chat/ChatHeader";
44
- export { default as ChatIdentity } from "./ui/chat/ChatIdentity";
45
- export { default as ChatMessageItem } from "./ui/chat/ChatMessageItem";
46
- export { default as ChatScroll } from "./ui/chat/ChatScroll";
47
- export { default as ChatThreadItem } from "./ui/chat/ChatThreadItem";
48
- export type { ChatThreadStatus } from "./ui/chat/ChatThreadItem";
49
- export { default as ChatListHeader } from "./ui/chat/ChatListHeader";
50
- export { default as ChatInquiryBar } from "./ui/chat/ChatInquiryBar";
51
- export { default as TypingIndicator } from "./ui/chat/TypingIndicator";
52
- export { default as ReplyCard } from "./ui/chat/ReplyCard";
53
- export { default as ChatSpinner } from "./ui/chat/ChatSpinner";
42
+ export { default as ChatFooter } from "./ui/ChatFooter";
43
+ export { default as ChatHeader } from "./ui/ChatHeader";
44
+ export { default as ChatIdentity } from "./ui/ChatIdentity";
45
+ export { default as ChatMessageItem } from "./ui/ChatMessageItem";
46
+ export { default as ChatScroll } from "./ui/ChatScroll";
47
+ export { default as ChatThreadItem } from "./ui/ChatThreadItem";
48
+ export type { ChatThreadStatus } from "./ui/ChatThreadItem";
49
+ export { default as ChatListHeader } from "./ui/ChatListHeader";
50
+ export { default as ChatInquiryBar } from "./ui/ChatInquiryBar";
51
+ export { default as TypingIndicator } from "./ui/TypingIndicator";
52
+ export { default as ReplyCard } from "./ui/ReplyCard";
53
+ export { default as ChatSpinner } from "./ui/ChatSpinner";
54
+ export { default as ChatKebabMenu } from "./ui/ChatKebabMenu";
55
+ export type { ChatKebabMenuProps } from "./ui/ChatKebabMenu";
54
56
 
55
57
  // ── Utilities ─────────────────────────────────────────────────────────────────
56
58
  export { cn } from "./utils/cn";