@banbox/chat 1.0.3 → 1.0.4

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.
@@ -1,64 +1,71 @@
1
- "use client";
2
- import clsx from "clsx";
3
- import React from "react";
4
-
5
- type Props = {
6
- top?: React.ReactNode;
7
- children: React.ReactNode;
8
- className?: string;
9
- /** set true if you want short threads anchored at the bottom */
10
- bottomAlignWhenShort?: boolean;
11
- /** when this value changes, we auto-scroll to the bottom */
12
- scrollKey?: string | number;
13
- };
14
-
15
- const ChatScroll: React.FC<Props> = ({
16
- top,
17
- children,
18
- className,
19
- bottomAlignWhenShort = false,
20
- scrollKey,
21
- }) => {
22
- const ref = React.useRef<HTMLDivElement>(null);
23
-
24
- const scrollToBottom = React.useCallback(() => {
25
- const el = ref.current;
26
- if (!el) {
27
- return;
28
- }
29
- el.scrollTop = el.scrollHeight;
30
- }, []);
31
-
32
- // On mount & when scrollKey changes
33
- React.useEffect(() => {
34
- // immediate
35
- scrollToBottom();
36
- // nudge after paint/layout (covers images)
37
- const id = window.setTimeout(scrollToBottom, 0);
38
- return () => window.clearTimeout(id);
39
- }, [scrollKey, scrollToBottom]);
40
-
41
- return (
42
- <div
43
- ref={ref}
44
- data-chat-scroll
45
- className={clsx(
46
- "h-full min-h-0 overflow-y-auto bg-white p-4 custom-scroll-hidden",
47
- className,
48
- )}
49
- >
50
- {/* This wrapper ensures content is at least as tall as the scroll area */}
51
- <div
52
- className={clsx(
53
- "min-h-full flex flex-col",
54
- bottomAlignWhenShort ? "justify-end" : "justify-start",
55
- )}
56
- >
57
- {top}
58
- {children}
59
- </div>
60
- </div>
61
- );
62
- };
63
-
64
- export default ChatScroll;
1
+ "use client";
2
+ import React from "react";
3
+
4
+ type Props = {
5
+ top?: React.ReactNode;
6
+ children: React.ReactNode;
7
+ className?: string;
8
+ style?: React.CSSProperties;
9
+ /** set true if you want short threads anchored at the bottom */
10
+ bottomAlignWhenShort?: boolean;
11
+ /** when this value changes, we auto-scroll to the bottom */
12
+ scrollKey?: string | number;
13
+ };
14
+
15
+ const ChatScroll: React.FC<Props> = ({
16
+ top,
17
+ children,
18
+ style,
19
+ bottomAlignWhenShort = false,
20
+ scrollKey,
21
+ }) => {
22
+ const ref = React.useRef<HTMLDivElement>(null);
23
+
24
+ const scrollToBottom = React.useCallback(() => {
25
+ const el = ref.current;
26
+ if (!el) {
27
+ return;
28
+ }
29
+ el.scrollTop = el.scrollHeight;
30
+ }, []);
31
+
32
+ // On mount & when scrollKey changes
33
+ React.useEffect(() => {
34
+ scrollToBottom();
35
+ const id = window.setTimeout(scrollToBottom, 0);
36
+ return () => window.clearTimeout(id);
37
+ }, [scrollKey, scrollToBottom]);
38
+
39
+ return (
40
+ <div
41
+ ref={ref}
42
+ data-chat-scroll
43
+ style={{
44
+ height: "100%",
45
+ minHeight: 0,
46
+ overflowY: "auto",
47
+ backgroundColor: "#fff",
48
+ padding: 16,
49
+ // custom scrollbar — hide track for clean look
50
+ scrollbarWidth: "thin",
51
+ scrollbarColor: "#d1d5db transparent",
52
+ ...style,
53
+ }}
54
+ >
55
+ {/* Ensures content is at least as tall as the scroll area */}
56
+ <div
57
+ style={{
58
+ minHeight: "100%",
59
+ display: "flex",
60
+ flexDirection: "column",
61
+ justifyContent: bottomAlignWhenShort ? "flex-end" : "flex-start",
62
+ }}
63
+ >
64
+ {top}
65
+ {children}
66
+ </div>
67
+ </div>
68
+ );
69
+ };
70
+
71
+ export default ChatScroll;
@@ -6,7 +6,6 @@ import _Lottie from "lottie-react";
6
6
  const Lottie = ((_Lottie as any).default ?? _Lottie) as typeof _Lottie;
7
7
 
8
8
  import React from "react";
9
- import { cn } from "../../utils/cn";
10
9
  import dots from "../../lottie/typingdotanimation2.json";
11
10
 
12
11
  /* =======================
@@ -14,15 +13,13 @@ import dots from "../../lottie/typingdotanimation2.json";
14
13
  ======================= */
15
14
 
16
15
  type Props = {
17
- /** Pixel box for the animation area */
18
- size?: number; // default 18 (inside badge)
19
- loop?: boolean; // default true
20
- autoplay?: boolean; // default true
16
+ size?: number;
17
+ loop?: boolean;
18
+ autoplay?: boolean;
21
19
  className?: string;
20
+ style?: React.CSSProperties;
22
21
  ariaLabel?: string;
23
-
24
- /** Avatar size in px */
25
- avatarSize?: number; // default 40
22
+ avatarSize?: number;
26
23
  };
27
24
 
28
25
  /* =======================
@@ -30,39 +27,61 @@ type Props = {
30
27
  ======================= */
31
28
 
32
29
  const TypingIndicator: React.FC<Props> = ({
33
- size = 18,
34
30
  loop = true,
35
31
  autoplay = true,
36
- className,
37
32
  ariaLabel = "Typing…",
38
33
  avatarSize = 40,
34
+ style,
39
35
  }) => {
40
36
  const isOnline = true;
41
37
 
42
38
  return (
43
39
  <div
44
- className={cn("relative flex items-end gap-[6px]", className)}
45
40
  role="status"
46
41
  aria-label={ariaLabel}
42
+ style={{
43
+ position: "relative",
44
+ display: "flex",
45
+ alignItems: "flex-end",
46
+ gap: 6,
47
+ ...style,
48
+ }}
47
49
  >
48
50
  {/* Avatar */}
49
51
  <div
50
- className="relative shrink-0 rounded-full border border-[#F1F1F1]"
51
- style={{ width: avatarSize, height: avatarSize }}
52
+ style={{
53
+ position: "relative",
54
+ flexShrink: 0,
55
+ borderRadius: "50%",
56
+ border: "1px solid #F1F1F1",
57
+ width: avatarSize,
58
+ height: avatarSize,
59
+ }}
52
60
  >
53
61
  <img
54
62
  src="/chat/img/girl_support.png"
55
63
  alt="avatar image"
56
- className="h-full w-full rounded-full object-cover"
64
+ style={{ height: "100%", width: "100%", borderRadius: "50%", objectFit: "cover" }}
57
65
  />
58
66
 
59
67
  {isOnline && (
60
- <span className="absolute bottom-[0px] right-[0px] h-[11.25px] w-[11.25px] rounded-full bg-[#328545] ring-1 ring-white" />
68
+ <span
69
+ style={{
70
+ position: "absolute",
71
+ bottom: 0,
72
+ right: 0,
73
+ height: 11.25,
74
+ width: 11.25,
75
+ borderRadius: "50%",
76
+ backgroundColor: "#328545",
77
+ outline: "2px solid #fff",
78
+ }}
79
+ />
61
80
  )}
62
81
  </div>
63
82
 
64
- {/* typing lottie at bottom-right */}
65
- <span className="absolute bottom-[-13px] left-[30px]">
83
+ {/* Lottie typing dots */}
84
+ <span style={{ position: "absolute", bottom: -13, left: 30 }}>
66
85
  <Lottie
67
86
  animationData={dots}
68
87
  loop={loop}