@better-zap/react 0.2.0 → 0.2.2
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.
- package/dist/bubble.cjs +93 -0
- package/dist/bubble.d.cts +61 -0
- package/dist/bubble.d.mts +61 -0
- package/dist/bubble.mjs +89 -0
- package/dist/composer.cjs +220 -0
- package/dist/composer.d.cts +96 -0
- package/dist/composer.d.mts +96 -0
- package/dist/composer.mjs +211 -0
- package/dist/conversation-list-BlhJhDsc.d.cts +100 -0
- package/dist/conversation-list-BwQ4oK2J.d.mts +100 -0
- package/dist/conversation-list-C0EmReS-.mjs +293 -0
- package/dist/conversation-list-CVWdddJh.cjs +311 -0
- package/dist/conversation-list.cjs +6 -0
- package/dist/conversation-list.d.cts +2 -0
- package/dist/conversation-list.d.mts +2 -0
- package/dist/conversation-list.mjs +5 -0
- package/dist/index.cjs +49 -0
- package/dist/index.d.cts +19 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.mjs +11 -0
- package/dist/message-bubble.cjs +116 -0
- package/dist/message-bubble.d.cts +38 -0
- package/dist/message-bubble.d.mts +38 -0
- package/dist/message-bubble.mjs +114 -0
- package/dist/message-input-CkaL6fb4.mjs +173 -0
- package/dist/message-input-DcEzHQ9t.cjs +191 -0
- package/dist/message-input.cjs +6 -0
- package/dist/message-input.d.cts +51 -0
- package/dist/message-input.d.mts +51 -0
- package/dist/message-input.mjs +5 -0
- package/dist/message-view.cjs +273 -0
- package/dist/message-view.d.cts +109 -0
- package/dist/message-view.d.mts +109 -0
- package/dist/message-view.mjs +266 -0
- package/dist/message.cjs +50 -0
- package/dist/message.d.cts +40 -0
- package/dist/message.d.mts +40 -0
- package/dist/message.mjs +43 -0
- package/dist/tailwind.css +33 -0
- package/dist/utils-Bp9IahGG.cjs +91 -0
- package/dist/utils.cjs +5 -0
- package/dist/utils.d.cts +20 -0
- package/dist/utils.d.mts +20 -0
- package/dist/utils.mjs +45 -0
- package/dist/whatsapp-dashboard.cjs +64 -0
- package/dist/whatsapp-dashboard.d.cts +33 -0
- package/dist/whatsapp-dashboard.d.mts +33 -0
- package/dist/whatsapp-dashboard.mjs +60 -0
- package/dist/wpp-bg.webp +0 -0
- package/package.json +1 -1
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Bubble, BubbleAlign, BubbleContent, BubbleContentProps, BubbleGroup, BubbleGroupProps, BubbleProps, BubbleReactions, BubbleReactionsProps, BubbleVariant } from "./bubble.cjs";
|
|
2
|
+
import { Composer, ComposerButton, ComposerButtonProps, ComposerContextValue, ComposerError, ComposerErrorProps, ComposerProps, ComposerSend, ComposerSendProps, ComposerStateContextValue, ComposerTextarea, ComposerTextareaProps, useComposer, useComposerState, useComposerValue } from "./composer.cjs";
|
|
3
|
+
import { a as ConversationListProps, c as ConversationFilterValue, i as ConversationListLabels, n as ConversationItemProps, o as ConversationFilterChips, r as ConversationList, s as ConversationFilterChipsProps, t as ConversationItem } from "./conversation-list-BlhJhDsc.cjs";
|
|
4
|
+
import { MobileView, WhatsappDashboard, WhatsappDashboardContextValue, WhatsappDashboardProps, useOptionalWhatsappDashboard, useWhatsappDashboard } from "./whatsapp-dashboard.cjs";
|
|
5
|
+
import { DateDivider, DateDividerRenderContext, MessageGroupPosition, MessageList, MessageListProps, MessageRenderContext, MessageView, MessageViewContent, MessageViewContentProps, MessageViewEmpty, MessageViewHeader, MessageViewHeaderLabels, MessageViewHeaderProps, MessageViewProps } from "./message-view.cjs";
|
|
6
|
+
import { FormattedMessage, MessageBubble, MessageBubbleGroupPosition, MessageBubbleProps } from "./message-bubble.cjs";
|
|
7
|
+
import { Message, MessageAlign, MessageAvatar, MessageAvatarProps, MessageContent, MessageContentProps, MessageFooter, MessageFooterProps, MessageGroup, MessageGroupProps, MessageHeader, MessageHeaderProps, MessageProps } from "./message.cjs";
|
|
8
|
+
import { cn, getDisplayDate, renderSlot } from "./utils.cjs";
|
|
9
|
+
import { FreeformWindowClosedError, MessageInput, MessageInputLabels, MessageInputProps } from "./message-input.cjs";
|
|
10
|
+
import { Conversation, Conversation as Conversation$1, ConversationRecord, FreeformMessageWindow, FreeformMessageWindow as FreeformMessageWindow$1, UIMessage, UIMessage as UIMessage$1, UIMessageStatus } from "better-zap";
|
|
11
|
+
|
|
12
|
+
//#region src/use-freeform-message-window.d.ts
|
|
13
|
+
interface UseFreeformMessageWindowResult extends FreeformMessageWindow$1 {
|
|
14
|
+
/** Recompute with a fresh clock, update state, and return the fresh result. */
|
|
15
|
+
revalidate: () => FreeformMessageWindow$1;
|
|
16
|
+
}
|
|
17
|
+
declare function useFreeformMessageWindow(conversation?: Pick<Conversation$1, "freeformMessageWindow" | "lastIncomingMessageAt"> | null, messages?: UIMessage$1[]): UseFreeformMessageWindowResult;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { Bubble, BubbleAlign, BubbleContent, BubbleContentProps, BubbleGroup, BubbleGroupProps, BubbleProps, BubbleReactions, BubbleReactionsProps, BubbleVariant, Composer, ComposerButton, ComposerButtonProps, ComposerContextValue, ComposerError, ComposerErrorProps, ComposerProps, ComposerSend, ComposerSendProps, ComposerStateContextValue, ComposerTextarea, ComposerTextareaProps, type Conversation, ConversationFilterChips, ConversationFilterChipsProps, ConversationFilterValue, ConversationItem, ConversationItemProps, ConversationList, ConversationListLabels, ConversationListProps, type ConversationRecord, DateDivider, DateDividerRenderContext, FormattedMessage, type FreeformMessageWindow, FreeformWindowClosedError, Message, MessageAlign, MessageAvatar, MessageAvatarProps, MessageBubble, MessageBubbleGroupPosition, MessageBubbleProps, MessageContent, MessageContentProps, MessageFooter, MessageFooterProps, MessageGroup, MessageGroupPosition, MessageGroupProps, MessageHeader, MessageHeaderProps, MessageInput, MessageInputLabels, MessageInputProps, MessageList, MessageListProps, MessageProps, MessageRenderContext, MessageView, MessageViewContent, MessageViewContentProps, MessageViewEmpty, MessageViewHeader, MessageViewHeaderLabels, MessageViewHeaderProps, MessageViewProps, MobileView, type UIMessage, type UIMessageStatus, UseFreeformMessageWindowResult, WhatsappDashboard, WhatsappDashboardContextValue, WhatsappDashboardProps, cn, getDisplayDate, renderSlot, useComposer, useComposerState, useComposerValue, useFreeformMessageWindow, useOptionalWhatsappDashboard, useWhatsappDashboard };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Bubble, BubbleAlign, BubbleContent, BubbleContentProps, BubbleGroup, BubbleGroupProps, BubbleProps, BubbleReactions, BubbleReactionsProps, BubbleVariant } from "./bubble.mjs";
|
|
2
|
+
import { Composer, ComposerButton, ComposerButtonProps, ComposerContextValue, ComposerError, ComposerErrorProps, ComposerProps, ComposerSend, ComposerSendProps, ComposerStateContextValue, ComposerTextarea, ComposerTextareaProps, useComposer, useComposerState, useComposerValue } from "./composer.mjs";
|
|
3
|
+
import { a as ConversationListProps, c as ConversationFilterValue, i as ConversationListLabels, n as ConversationItemProps, o as ConversationFilterChips, r as ConversationList, s as ConversationFilterChipsProps, t as ConversationItem } from "./conversation-list-BwQ4oK2J.mjs";
|
|
4
|
+
import { MobileView, WhatsappDashboard, WhatsappDashboardContextValue, WhatsappDashboardProps, useOptionalWhatsappDashboard, useWhatsappDashboard } from "./whatsapp-dashboard.mjs";
|
|
5
|
+
import { DateDivider, DateDividerRenderContext, MessageGroupPosition, MessageList, MessageListProps, MessageRenderContext, MessageView, MessageViewContent, MessageViewContentProps, MessageViewEmpty, MessageViewHeader, MessageViewHeaderLabels, MessageViewHeaderProps, MessageViewProps } from "./message-view.mjs";
|
|
6
|
+
import { FormattedMessage, MessageBubble, MessageBubbleGroupPosition, MessageBubbleProps } from "./message-bubble.mjs";
|
|
7
|
+
import { Message, MessageAlign, MessageAvatar, MessageAvatarProps, MessageContent, MessageContentProps, MessageFooter, MessageFooterProps, MessageGroup, MessageGroupProps, MessageHeader, MessageHeaderProps, MessageProps } from "./message.mjs";
|
|
8
|
+
import { cn, getDisplayDate, renderSlot } from "./utils.mjs";
|
|
9
|
+
import { FreeformWindowClosedError, MessageInput, MessageInputLabels, MessageInputProps } from "./message-input.mjs";
|
|
10
|
+
import { Conversation, Conversation as Conversation$1, ConversationRecord, FreeformMessageWindow, FreeformMessageWindow as FreeformMessageWindow$1, UIMessage, UIMessage as UIMessage$1, UIMessageStatus } from "better-zap";
|
|
11
|
+
|
|
12
|
+
//#region src/use-freeform-message-window.d.ts
|
|
13
|
+
interface UseFreeformMessageWindowResult extends FreeformMessageWindow$1 {
|
|
14
|
+
/** Recompute with a fresh clock, update state, and return the fresh result. */
|
|
15
|
+
revalidate: () => FreeformMessageWindow$1;
|
|
16
|
+
}
|
|
17
|
+
declare function useFreeformMessageWindow(conversation?: Pick<Conversation$1, "freeformMessageWindow" | "lastIncomingMessageAt"> | null, messages?: UIMessage$1[]): UseFreeformMessageWindowResult;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { Bubble, BubbleAlign, BubbleContent, BubbleContentProps, BubbleGroup, BubbleGroupProps, BubbleProps, BubbleReactions, BubbleReactionsProps, BubbleVariant, Composer, ComposerButton, ComposerButtonProps, ComposerContextValue, ComposerError, ComposerErrorProps, ComposerProps, ComposerSend, ComposerSendProps, ComposerStateContextValue, ComposerTextarea, ComposerTextareaProps, type Conversation, ConversationFilterChips, ConversationFilterChipsProps, ConversationFilterValue, ConversationItem, ConversationItemProps, ConversationList, ConversationListLabels, ConversationListProps, type ConversationRecord, DateDivider, DateDividerRenderContext, FormattedMessage, type FreeformMessageWindow, FreeformWindowClosedError, Message, MessageAlign, MessageAvatar, MessageAvatarProps, MessageBubble, MessageBubbleGroupPosition, MessageBubbleProps, MessageContent, MessageContentProps, MessageFooter, MessageFooterProps, MessageGroup, MessageGroupPosition, MessageGroupProps, MessageHeader, MessageHeaderProps, MessageInput, MessageInputLabels, MessageInputProps, MessageList, MessageListProps, MessageProps, MessageRenderContext, MessageView, MessageViewContent, MessageViewContentProps, MessageViewEmpty, MessageViewHeader, MessageViewHeaderLabels, MessageViewHeaderProps, MessageViewProps, MobileView, type UIMessage, type UIMessageStatus, UseFreeformMessageWindowResult, WhatsappDashboard, WhatsappDashboardContextValue, WhatsappDashboardProps, cn, getDisplayDate, renderSlot, useComposer, useComposerState, useComposerValue, useFreeformMessageWindow, useOptionalWhatsappDashboard, useWhatsappDashboard };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn, getDisplayDate, renderSlot } from "./utils.mjs";
|
|
3
|
+
import { WhatsappDashboard, useOptionalWhatsappDashboard, useWhatsappDashboard } from "./whatsapp-dashboard.mjs";
|
|
4
|
+
import { Bubble, BubbleContent, BubbleGroup, BubbleReactions } from "./bubble.mjs";
|
|
5
|
+
import { Message, MessageAvatar, MessageContent, MessageFooter, MessageGroup, MessageHeader } from "./message.mjs";
|
|
6
|
+
import { FormattedMessage, MessageBubble } from "./message-bubble.mjs";
|
|
7
|
+
import { DateDivider, MessageList, MessageView, MessageViewContent, MessageViewEmpty, MessageViewHeader } from "./message-view.mjs";
|
|
8
|
+
import { n as ConversationList, r as ConversationFilterChips, t as ConversationItem } from "./conversation-list-C0EmReS-.mjs";
|
|
9
|
+
import { Composer, ComposerButton, ComposerError, ComposerSend, ComposerTextarea, useComposer, useComposerState, useComposerValue } from "./composer.mjs";
|
|
10
|
+
import { n as MessageInput, r as useFreeformMessageWindow, t as FreeformWindowClosedError } from "./message-input-CkaL6fb4.mjs";
|
|
11
|
+
export { Bubble, BubbleContent, BubbleGroup, BubbleReactions, Composer, ComposerButton, ComposerError, ComposerSend, ComposerTextarea, ConversationFilterChips, ConversationItem, ConversationList, DateDivider, FormattedMessage, FreeformWindowClosedError, Message, MessageAvatar, MessageBubble, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageInput, MessageList, MessageView, MessageViewContent, MessageViewEmpty, MessageViewHeader, WhatsappDashboard, cn, getDisplayDate, renderSlot, useComposer, useComposerState, useComposerValue, useFreeformMessageWindow, useOptionalWhatsappDashboard, useWhatsappDashboard };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_utils = require("./utils-Bp9IahGG.cjs");
|
|
3
|
+
const require_bubble = require("./bubble.cjs");
|
|
4
|
+
const require_message = require("./message.cjs");
|
|
5
|
+
let react = require("react");
|
|
6
|
+
react = require_utils.__toESM(react);
|
|
7
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
|
+
let _hugeicons_react = require("@hugeicons/react");
|
|
9
|
+
let _hugeicons_core_free_icons = require("@hugeicons/core-free-icons");
|
|
10
|
+
//#region src/message-bubble.tsx
|
|
11
|
+
const statusVariants = (0, require("class-variance-authority").cva)("flex items-center leading-none", {
|
|
12
|
+
variants: { variant: {
|
|
13
|
+
default: "text-[#111b21]/40",
|
|
14
|
+
read: "text-[#53bdeb]",
|
|
15
|
+
failed: "text-red-500"
|
|
16
|
+
} },
|
|
17
|
+
defaultVariants: { variant: "default" }
|
|
18
|
+
});
|
|
19
|
+
function MessageBubble({ content, sender, timestamp, status, templateName, label, groupPosition = "single", className, ...props }) {
|
|
20
|
+
const isIncoming = sender === "user";
|
|
21
|
+
const isFailed = status === "failed";
|
|
22
|
+
const align = sender === "user" ? "start" : "end";
|
|
23
|
+
const variant = sender === "user" ? "default" : status === "failed" ? "destructive" : "primary";
|
|
24
|
+
const statusVariant = status === "read" ? "read" : isFailed ? "failed" : "default";
|
|
25
|
+
const statusIcon = isFailed ? _hugeicons_core_free_icons.Alert02Icon : status === "read" || status === "delivered" ? _hugeicons_core_free_icons.TickDouble02Icon : _hugeicons_core_free_icons.Tick02Icon;
|
|
26
|
+
const hasTail = groupPosition === "single" || groupPosition === "first";
|
|
27
|
+
const endsGroup = groupPosition === "single" || groupPosition === "last";
|
|
28
|
+
const displayContent = content || (templateName ? `[Template: ${templateName}]` : "[Conteúdo não disponível]");
|
|
29
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_message.Message, {
|
|
30
|
+
align,
|
|
31
|
+
className: require_utils.cn(endsGroup ? "mb-3" : "mb-0.5", className),
|
|
32
|
+
...props,
|
|
33
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_message.MessageContent, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_bubble.Bubble, {
|
|
34
|
+
variant,
|
|
35
|
+
align,
|
|
36
|
+
tail: hasTail,
|
|
37
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_bubble.BubbleContent, { children: [
|
|
38
|
+
label && !isIncoming && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
39
|
+
className: "mb-1 block text-xs font-medium opacity-70",
|
|
40
|
+
children: label
|
|
41
|
+
}),
|
|
42
|
+
templateName && !label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
43
|
+
className: "mb-1 border-b border-black/5 pb-1",
|
|
44
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
45
|
+
className: "flex items-center gap-1 text-[11px] font-medium opacity-70",
|
|
46
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_hugeicons_react.HugeiconsIcon, {
|
|
47
|
+
icon: _hugeicons_core_free_icons.File02Icon,
|
|
48
|
+
size: 12
|
|
49
|
+
}), templateName]
|
|
50
|
+
})
|
|
51
|
+
}),
|
|
52
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormattedMessage, { text: displayContent }),
|
|
53
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
54
|
+
className: "float-right -mb-1 ml-2 mt-1.5 flex items-center justify-end gap-1 shrink-0 h-[15px] select-none",
|
|
55
|
+
children: [timestamp && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
56
|
+
className: "text-[11px] text-[#111b21]/60 leading-none whitespace-nowrap",
|
|
57
|
+
children: timestamp
|
|
58
|
+
}), !isIncoming && status && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59
|
+
role: "img",
|
|
60
|
+
"aria-label": String(status),
|
|
61
|
+
"data-status": status,
|
|
62
|
+
className: statusVariants({ variant: statusVariant }),
|
|
63
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_hugeicons_react.HugeiconsIcon, {
|
|
64
|
+
icon: statusIcon,
|
|
65
|
+
size: 15,
|
|
66
|
+
strokeWidth: 2
|
|
67
|
+
})
|
|
68
|
+
})]
|
|
69
|
+
}),
|
|
70
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "clear-both" })
|
|
71
|
+
] })
|
|
72
|
+
}) })
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function FormattedMessage({ text }) {
|
|
76
|
+
if (!text) return null;
|
|
77
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: text.split(/(\n)/g).map((line, lineIndex) => {
|
|
78
|
+
if (line === "\n") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}, lineIndex);
|
|
79
|
+
if (!line) return null;
|
|
80
|
+
const parts = line.split(/(```[\s\S]*?```|`[^`]+`|\*[^\s*](?:[^*]*[^\s*])?\*|_[^\s_](?:[^_]*[^\s_])?_|~[^\s~](?:[^~]*[^\s~])?~|https?:\/\/[^\s]+)/g);
|
|
81
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: parts.map((part, index) => {
|
|
82
|
+
if (!part) return null;
|
|
83
|
+
if (part.startsWith("```") && part.endsWith("```")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
84
|
+
className: "my-1 block whitespace-pre-wrap rounded bg-black/5 px-1 py-0.5 font-mono text-[13px]",
|
|
85
|
+
children: part.slice(3, -3)
|
|
86
|
+
}, index);
|
|
87
|
+
if (part.startsWith("`") && part.endsWith("`")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
88
|
+
className: "rounded bg-black/5 px-1 font-mono text-[13px] text-[#df0165]",
|
|
89
|
+
children: part.slice(1, -1)
|
|
90
|
+
}, index);
|
|
91
|
+
if (part.startsWith("*") && part.endsWith("*")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
92
|
+
className: "font-bold",
|
|
93
|
+
children: part.slice(1, -1)
|
|
94
|
+
}, index);
|
|
95
|
+
if (part.startsWith("_") && part.endsWith("_")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("em", {
|
|
96
|
+
className: "italic",
|
|
97
|
+
children: part.slice(1, -1)
|
|
98
|
+
}, index);
|
|
99
|
+
if (part.startsWith("~") && part.endsWith("~")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("del", {
|
|
100
|
+
className: "text-gray-500 line-through",
|
|
101
|
+
children: part.slice(1, -1)
|
|
102
|
+
}, index);
|
|
103
|
+
if (part.match(/^https?:\/\/[^\s]+$/)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
104
|
+
href: part,
|
|
105
|
+
target: "_blank",
|
|
106
|
+
rel: "noopener noreferrer",
|
|
107
|
+
className: "text-[#027eb5] hover:underline",
|
|
108
|
+
children: part
|
|
109
|
+
}, index);
|
|
110
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: part }, index);
|
|
111
|
+
}) }, lineIndex);
|
|
112
|
+
}) });
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
exports.FormattedMessage = FormattedMessage;
|
|
116
|
+
exports.MessageBubble = MessageBubble;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
import { UIMessageStatus } from "better-zap";
|
|
4
|
+
|
|
5
|
+
//#region src/message-bubble.d.ts
|
|
6
|
+
type MessageBubbleGroupPosition = "single" | "first" | "middle" | "last";
|
|
7
|
+
interface MessageBubbleProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
content: string;
|
|
9
|
+
sender: "user" | "bot";
|
|
10
|
+
timestamp?: string;
|
|
11
|
+
status?: UIMessageStatus | string;
|
|
12
|
+
templateName?: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Position within a run of same-direction messages. Controls the corner
|
|
16
|
+
* tail (first/single only) and the gap to the next message, mirroring
|
|
17
|
+
* WhatsApp's grouping. @default "single"
|
|
18
|
+
*/
|
|
19
|
+
groupPosition?: MessageBubbleGroupPosition;
|
|
20
|
+
}
|
|
21
|
+
declare function MessageBubble({
|
|
22
|
+
content,
|
|
23
|
+
sender,
|
|
24
|
+
timestamp,
|
|
25
|
+
status,
|
|
26
|
+
templateName,
|
|
27
|
+
label,
|
|
28
|
+
groupPosition,
|
|
29
|
+
className,
|
|
30
|
+
...props
|
|
31
|
+
}: MessageBubbleProps): react_jsx_runtime0.JSX.Element;
|
|
32
|
+
declare function FormattedMessage({
|
|
33
|
+
text
|
|
34
|
+
}: {
|
|
35
|
+
text: string;
|
|
36
|
+
}): react_jsx_runtime0.JSX.Element | null;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { FormattedMessage, MessageBubble, MessageBubbleGroupPosition, MessageBubbleProps };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
import { UIMessageStatus } from "better-zap";
|
|
4
|
+
|
|
5
|
+
//#region src/message-bubble.d.ts
|
|
6
|
+
type MessageBubbleGroupPosition = "single" | "first" | "middle" | "last";
|
|
7
|
+
interface MessageBubbleProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
content: string;
|
|
9
|
+
sender: "user" | "bot";
|
|
10
|
+
timestamp?: string;
|
|
11
|
+
status?: UIMessageStatus | string;
|
|
12
|
+
templateName?: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Position within a run of same-direction messages. Controls the corner
|
|
16
|
+
* tail (first/single only) and the gap to the next message, mirroring
|
|
17
|
+
* WhatsApp's grouping. @default "single"
|
|
18
|
+
*/
|
|
19
|
+
groupPosition?: MessageBubbleGroupPosition;
|
|
20
|
+
}
|
|
21
|
+
declare function MessageBubble({
|
|
22
|
+
content,
|
|
23
|
+
sender,
|
|
24
|
+
timestamp,
|
|
25
|
+
status,
|
|
26
|
+
templateName,
|
|
27
|
+
label,
|
|
28
|
+
groupPosition,
|
|
29
|
+
className,
|
|
30
|
+
...props
|
|
31
|
+
}: MessageBubbleProps): react_jsx_runtime0.JSX.Element;
|
|
32
|
+
declare function FormattedMessage({
|
|
33
|
+
text
|
|
34
|
+
}: {
|
|
35
|
+
text: string;
|
|
36
|
+
}): react_jsx_runtime0.JSX.Element | null;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { FormattedMessage, MessageBubble, MessageBubbleGroupPosition, MessageBubbleProps };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { cn } from "./utils.mjs";
|
|
2
|
+
import { Bubble, BubbleContent } from "./bubble.mjs";
|
|
3
|
+
import { Message, MessageContent } from "./message.mjs";
|
|
4
|
+
import React from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { HugeiconsIcon } from "@hugeicons/react";
|
|
7
|
+
import { Alert02Icon, File02Icon, Tick02Icon, TickDouble02Icon } from "@hugeicons/core-free-icons";
|
|
8
|
+
import { cva } from "class-variance-authority";
|
|
9
|
+
//#region src/message-bubble.tsx
|
|
10
|
+
const statusVariants = cva("flex items-center leading-none", {
|
|
11
|
+
variants: { variant: {
|
|
12
|
+
default: "text-[#111b21]/40",
|
|
13
|
+
read: "text-[#53bdeb]",
|
|
14
|
+
failed: "text-red-500"
|
|
15
|
+
} },
|
|
16
|
+
defaultVariants: { variant: "default" }
|
|
17
|
+
});
|
|
18
|
+
function MessageBubble({ content, sender, timestamp, status, templateName, label, groupPosition = "single", className, ...props }) {
|
|
19
|
+
const isIncoming = sender === "user";
|
|
20
|
+
const isFailed = status === "failed";
|
|
21
|
+
const align = sender === "user" ? "start" : "end";
|
|
22
|
+
const variant = sender === "user" ? "default" : status === "failed" ? "destructive" : "primary";
|
|
23
|
+
const statusVariant = status === "read" ? "read" : isFailed ? "failed" : "default";
|
|
24
|
+
const statusIcon = isFailed ? Alert02Icon : status === "read" || status === "delivered" ? TickDouble02Icon : Tick02Icon;
|
|
25
|
+
const hasTail = groupPosition === "single" || groupPosition === "first";
|
|
26
|
+
const endsGroup = groupPosition === "single" || groupPosition === "last";
|
|
27
|
+
const displayContent = content || (templateName ? `[Template: ${templateName}]` : "[Conteúdo não disponível]");
|
|
28
|
+
return /* @__PURE__ */ jsx(Message, {
|
|
29
|
+
align,
|
|
30
|
+
className: cn(endsGroup ? "mb-3" : "mb-0.5", className),
|
|
31
|
+
...props,
|
|
32
|
+
children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(Bubble, {
|
|
33
|
+
variant,
|
|
34
|
+
align,
|
|
35
|
+
tail: hasTail,
|
|
36
|
+
children: /* @__PURE__ */ jsxs(BubbleContent, { children: [
|
|
37
|
+
label && !isIncoming && /* @__PURE__ */ jsx("span", {
|
|
38
|
+
className: "mb-1 block text-xs font-medium opacity-70",
|
|
39
|
+
children: label
|
|
40
|
+
}),
|
|
41
|
+
templateName && !label && /* @__PURE__ */ jsx("div", {
|
|
42
|
+
className: "mb-1 border-b border-black/5 pb-1",
|
|
43
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
44
|
+
className: "flex items-center gap-1 text-[11px] font-medium opacity-70",
|
|
45
|
+
children: [/* @__PURE__ */ jsx(HugeiconsIcon, {
|
|
46
|
+
icon: File02Icon,
|
|
47
|
+
size: 12
|
|
48
|
+
}), templateName]
|
|
49
|
+
})
|
|
50
|
+
}),
|
|
51
|
+
/* @__PURE__ */ jsx(FormattedMessage, { text: displayContent }),
|
|
52
|
+
/* @__PURE__ */ jsxs("div", {
|
|
53
|
+
className: "float-right -mb-1 ml-2 mt-1.5 flex items-center justify-end gap-1 shrink-0 h-[15px] select-none",
|
|
54
|
+
children: [timestamp && /* @__PURE__ */ jsx("span", {
|
|
55
|
+
className: "text-[11px] text-[#111b21]/60 leading-none whitespace-nowrap",
|
|
56
|
+
children: timestamp
|
|
57
|
+
}), !isIncoming && status && /* @__PURE__ */ jsx("span", {
|
|
58
|
+
role: "img",
|
|
59
|
+
"aria-label": String(status),
|
|
60
|
+
"data-status": status,
|
|
61
|
+
className: statusVariants({ variant: statusVariant }),
|
|
62
|
+
children: /* @__PURE__ */ jsx(HugeiconsIcon, {
|
|
63
|
+
icon: statusIcon,
|
|
64
|
+
size: 15,
|
|
65
|
+
strokeWidth: 2
|
|
66
|
+
})
|
|
67
|
+
})]
|
|
68
|
+
}),
|
|
69
|
+
/* @__PURE__ */ jsx("div", { className: "clear-both" })
|
|
70
|
+
] })
|
|
71
|
+
}) })
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function FormattedMessage({ text }) {
|
|
75
|
+
if (!text) return null;
|
|
76
|
+
return /* @__PURE__ */ jsx(Fragment, { children: text.split(/(\n)/g).map((line, lineIndex) => {
|
|
77
|
+
if (line === "\n") return /* @__PURE__ */ jsx("br", {}, lineIndex);
|
|
78
|
+
if (!line) return null;
|
|
79
|
+
const parts = line.split(/(```[\s\S]*?```|`[^`]+`|\*[^\s*](?:[^*]*[^\s*])?\*|_[^\s_](?:[^_]*[^\s_])?_|~[^\s~](?:[^~]*[^\s~])?~|https?:\/\/[^\s]+)/g);
|
|
80
|
+
return /* @__PURE__ */ jsx(React.Fragment, { children: parts.map((part, index) => {
|
|
81
|
+
if (!part) return null;
|
|
82
|
+
if (part.startsWith("```") && part.endsWith("```")) return /* @__PURE__ */ jsx("code", {
|
|
83
|
+
className: "my-1 block whitespace-pre-wrap rounded bg-black/5 px-1 py-0.5 font-mono text-[13px]",
|
|
84
|
+
children: part.slice(3, -3)
|
|
85
|
+
}, index);
|
|
86
|
+
if (part.startsWith("`") && part.endsWith("`")) return /* @__PURE__ */ jsx("code", {
|
|
87
|
+
className: "rounded bg-black/5 px-1 font-mono text-[13px] text-[#df0165]",
|
|
88
|
+
children: part.slice(1, -1)
|
|
89
|
+
}, index);
|
|
90
|
+
if (part.startsWith("*") && part.endsWith("*")) return /* @__PURE__ */ jsx("strong", {
|
|
91
|
+
className: "font-bold",
|
|
92
|
+
children: part.slice(1, -1)
|
|
93
|
+
}, index);
|
|
94
|
+
if (part.startsWith("_") && part.endsWith("_")) return /* @__PURE__ */ jsx("em", {
|
|
95
|
+
className: "italic",
|
|
96
|
+
children: part.slice(1, -1)
|
|
97
|
+
}, index);
|
|
98
|
+
if (part.startsWith("~") && part.endsWith("~")) return /* @__PURE__ */ jsx("del", {
|
|
99
|
+
className: "text-gray-500 line-through",
|
|
100
|
+
children: part.slice(1, -1)
|
|
101
|
+
}, index);
|
|
102
|
+
if (part.match(/^https?:\/\/[^\s]+$/)) return /* @__PURE__ */ jsx("a", {
|
|
103
|
+
href: part,
|
|
104
|
+
target: "_blank",
|
|
105
|
+
rel: "noopener noreferrer",
|
|
106
|
+
className: "text-[#027eb5] hover:underline",
|
|
107
|
+
children: part
|
|
108
|
+
}, index);
|
|
109
|
+
return /* @__PURE__ */ jsx("span", { children: part }, index);
|
|
110
|
+
}) }, lineIndex);
|
|
111
|
+
}) });
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
export { FormattedMessage, MessageBubble };
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { cn } from "./utils.mjs";
|
|
2
|
+
import { Composer, ComposerButton, ComposerError, ComposerSend, ComposerTextarea, useComposerState } from "./composer.mjs";
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { HugeiconsIcon } from "@hugeicons/react";
|
|
6
|
+
import { Add01Icon, Clock01Icon, Mic01Icon, SmileIcon } from "@hugeicons/core-free-icons";
|
|
7
|
+
import { resolveConversationFreeformMessageWindow } from "better-zap";
|
|
8
|
+
//#region src/use-freeform-message-window.ts
|
|
9
|
+
const CLOSED_WINDOW = {
|
|
10
|
+
isOpen: false,
|
|
11
|
+
lastIncomingMessageAt: null,
|
|
12
|
+
expiresAt: null
|
|
13
|
+
};
|
|
14
|
+
const MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
15
|
+
function useFreeformMessageWindow(conversation, messages) {
|
|
16
|
+
const [now, setNow] = useState(() => /* @__PURE__ */ new Date());
|
|
17
|
+
const freeformWindow = conversation ? resolveConversationFreeformMessageWindow(conversation, messages, now) : CLOSED_WINDOW;
|
|
18
|
+
const revalidate = useCallback(() => {
|
|
19
|
+
const freshNow = /* @__PURE__ */ new Date();
|
|
20
|
+
setNow(freshNow);
|
|
21
|
+
if (!conversation) return CLOSED_WINDOW;
|
|
22
|
+
return resolveConversationFreeformMessageWindow(conversation, messages, freshNow);
|
|
23
|
+
}, [conversation, messages]);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!conversation || !freeformWindow.isOpen || !freeformWindow.expiresAt) return;
|
|
26
|
+
const expiresAtMs = new Date(freeformWindow.expiresAt).getTime();
|
|
27
|
+
if (!Number.isFinite(expiresAtMs)) return;
|
|
28
|
+
const delay = Math.min(Math.max(0, expiresAtMs - Date.now()), MAX_TIMEOUT_MS);
|
|
29
|
+
const timeoutId = globalThis.setTimeout(() => {
|
|
30
|
+
setNow(/* @__PURE__ */ new Date());
|
|
31
|
+
}, delay);
|
|
32
|
+
return () => {
|
|
33
|
+
globalThis.clearTimeout(timeoutId);
|
|
34
|
+
};
|
|
35
|
+
}, [
|
|
36
|
+
conversation,
|
|
37
|
+
freeformWindow.isOpen,
|
|
38
|
+
freeformWindow.expiresAt,
|
|
39
|
+
now
|
|
40
|
+
]);
|
|
41
|
+
return {
|
|
42
|
+
...freeformWindow,
|
|
43
|
+
revalidate
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/message-input.tsx
|
|
48
|
+
var FreeformWindowClosedError = class extends Error {
|
|
49
|
+
window;
|
|
50
|
+
constructor(freeformWindow) {
|
|
51
|
+
super("Freeform messaging window is closed");
|
|
52
|
+
this.name = "FreeformWindowClosedError";
|
|
53
|
+
this.window = freeformWindow;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const DEFAULT_LABELS = {
|
|
57
|
+
sending: "Enviando...",
|
|
58
|
+
expired: "A janela de 24h expirou. Mensagens de texto livre só podem ser enviadas dentro de 24h após a última mensagem do contato.",
|
|
59
|
+
emoji: "Emojis",
|
|
60
|
+
attach: "Anexar arquivo",
|
|
61
|
+
send: "Enviar",
|
|
62
|
+
mic: "Gravar áudio",
|
|
63
|
+
textarea: "Mensagem",
|
|
64
|
+
sendFailed: "Falha ao enviar. Tente novamente."
|
|
65
|
+
};
|
|
66
|
+
function MessageInputBody({ labels, placeholder, onEmojiClick, onAttachClick, onMicClick, showDefaultError }) {
|
|
67
|
+
const { isSending, hasText } = useComposerState();
|
|
68
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
69
|
+
(onEmojiClick || onAttachClick) && /* @__PURE__ */ jsxs("div", {
|
|
70
|
+
className: "flex items-center gap-1 text-[#54656f] shrink-0",
|
|
71
|
+
children: [onEmojiClick && /* @__PURE__ */ jsx(ComposerButton, {
|
|
72
|
+
"aria-label": labels.emoji,
|
|
73
|
+
title: labels.emoji,
|
|
74
|
+
onClick: onEmojiClick,
|
|
75
|
+
children: /* @__PURE__ */ jsx(HugeiconsIcon, {
|
|
76
|
+
icon: SmileIcon,
|
|
77
|
+
size: 24
|
|
78
|
+
})
|
|
79
|
+
}), onAttachClick && /* @__PURE__ */ jsx(ComposerButton, {
|
|
80
|
+
"aria-label": labels.attach,
|
|
81
|
+
title: "Anexar",
|
|
82
|
+
onClick: onAttachClick,
|
|
83
|
+
children: /* @__PURE__ */ jsx(HugeiconsIcon, {
|
|
84
|
+
icon: Add01Icon,
|
|
85
|
+
size: 24
|
|
86
|
+
})
|
|
87
|
+
})]
|
|
88
|
+
}),
|
|
89
|
+
/* @__PURE__ */ jsx("div", {
|
|
90
|
+
className: "flex-1 flex items-center min-h-[40px] py-2 px-2",
|
|
91
|
+
children: /* @__PURE__ */ jsx(ComposerTextarea, {
|
|
92
|
+
"aria-label": labels.textarea,
|
|
93
|
+
placeholder: isSending ? labels.sending : placeholder
|
|
94
|
+
})
|
|
95
|
+
}),
|
|
96
|
+
/* @__PURE__ */ jsx("div", {
|
|
97
|
+
className: "flex items-center pr-1 shrink-0",
|
|
98
|
+
children: hasText ? /* @__PURE__ */ jsx(ComposerSend, { "aria-label": labels.send }) : onMicClick ? /* @__PURE__ */ jsx(ComposerButton, {
|
|
99
|
+
"aria-label": labels.mic,
|
|
100
|
+
className: "text-[#54656f]",
|
|
101
|
+
onClick: onMicClick,
|
|
102
|
+
children: /* @__PURE__ */ jsx(HugeiconsIcon, {
|
|
103
|
+
icon: Mic01Icon,
|
|
104
|
+
size: 24
|
|
105
|
+
})
|
|
106
|
+
}) : /* @__PURE__ */ jsx(ComposerSend, { "aria-label": labels.send })
|
|
107
|
+
}),
|
|
108
|
+
showDefaultError && /* @__PURE__ */ jsx(ComposerError, {
|
|
109
|
+
className: "px-2 pb-1 text-[13px] leading-[18px] text-red-600",
|
|
110
|
+
children: labels.sendFailed
|
|
111
|
+
})
|
|
112
|
+
] });
|
|
113
|
+
}
|
|
114
|
+
function MessageInput({ onSend, conversation, messages, disabled, placeholder = "Digite uma mensagem", className, contextWindowOpen = true, onSendError, onEmojiClick, onAttachClick, onMicClick, labels: labelsProp }) {
|
|
115
|
+
const labels = {
|
|
116
|
+
...DEFAULT_LABELS,
|
|
117
|
+
...labelsProp
|
|
118
|
+
};
|
|
119
|
+
const freeformFromHook = useFreeformMessageWindow(conversation, messages);
|
|
120
|
+
const freeformMessageWindow = conversation ? freeformFromHook : {
|
|
121
|
+
isOpen: contextWindowOpen,
|
|
122
|
+
lastIncomingMessageAt: null,
|
|
123
|
+
expiresAt: null,
|
|
124
|
+
revalidate: () => ({
|
|
125
|
+
isOpen: contextWindowOpen,
|
|
126
|
+
lastIncomingMessageAt: null,
|
|
127
|
+
expiresAt: null
|
|
128
|
+
})
|
|
129
|
+
};
|
|
130
|
+
const isContextWindowOpen = freeformMessageWindow.isOpen;
|
|
131
|
+
const revalidate = freeformMessageWindow.revalidate;
|
|
132
|
+
const handleSubmit = useCallback(async (text) => {
|
|
133
|
+
const windowState = revalidate();
|
|
134
|
+
if (!windowState.isOpen) throw new FreeformWindowClosedError(windowState);
|
|
135
|
+
return onSend(text);
|
|
136
|
+
}, [onSend, revalidate]);
|
|
137
|
+
const handleError = useCallback((error, context) => {
|
|
138
|
+
onSendError?.(error, context);
|
|
139
|
+
}, [onSendError]);
|
|
140
|
+
const showDefaultError = !(onSendError != null && labelsProp?.sendFailed === "");
|
|
141
|
+
if (!isContextWindowOpen) return /* @__PURE__ */ jsx("div", {
|
|
142
|
+
className: cn("w-full flex flex-col px-4 py-3 z-10 shrink-0", className),
|
|
143
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
144
|
+
className: "flex items-center gap-3 px-4 py-3 min-h-[52px] bg-[#ffeecd] rounded-[7.5px] shadow-[0_1px_0.5px_rgba(11,20,26,0.13)]",
|
|
145
|
+
children: [/* @__PURE__ */ jsx(HugeiconsIcon, {
|
|
146
|
+
icon: Clock01Icon,
|
|
147
|
+
size: 20,
|
|
148
|
+
className: "text-[#54656f] shrink-0"
|
|
149
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
150
|
+
className: "text-[13px] leading-[18px] text-[#54656f]",
|
|
151
|
+
children: labels.expired
|
|
152
|
+
})]
|
|
153
|
+
})
|
|
154
|
+
});
|
|
155
|
+
return /* @__PURE__ */ jsx("div", {
|
|
156
|
+
className: cn("w-full flex flex-col px-4 py-3 z-10 shrink-0", className),
|
|
157
|
+
children: /* @__PURE__ */ jsx(Composer, {
|
|
158
|
+
onSubmit: handleSubmit,
|
|
159
|
+
onError: handleError,
|
|
160
|
+
disabled,
|
|
161
|
+
children: /* @__PURE__ */ jsx(MessageInputBody, {
|
|
162
|
+
labels,
|
|
163
|
+
placeholder,
|
|
164
|
+
onEmojiClick,
|
|
165
|
+
onAttachClick,
|
|
166
|
+
onMicClick,
|
|
167
|
+
showDefaultError
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
export { MessageInput as n, useFreeformMessageWindow as r, FreeformWindowClosedError as t };
|