@better-zap/react 0.2.1 → 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.
Files changed (50) hide show
  1. package/dist/bubble.cjs +93 -0
  2. package/dist/bubble.d.cts +61 -0
  3. package/dist/bubble.d.mts +61 -0
  4. package/dist/bubble.mjs +89 -0
  5. package/dist/composer.cjs +220 -0
  6. package/dist/composer.d.cts +96 -0
  7. package/dist/composer.d.mts +96 -0
  8. package/dist/composer.mjs +211 -0
  9. package/dist/conversation-list-BlhJhDsc.d.cts +100 -0
  10. package/dist/conversation-list-BwQ4oK2J.d.mts +100 -0
  11. package/dist/conversation-list-C0EmReS-.mjs +293 -0
  12. package/dist/conversation-list-CVWdddJh.cjs +311 -0
  13. package/dist/conversation-list.cjs +6 -0
  14. package/dist/conversation-list.d.cts +2 -0
  15. package/dist/conversation-list.d.mts +2 -0
  16. package/dist/conversation-list.mjs +5 -0
  17. package/dist/index.cjs +49 -0
  18. package/dist/index.d.cts +19 -0
  19. package/dist/index.d.mts +19 -0
  20. package/dist/index.mjs +11 -0
  21. package/dist/message-bubble.cjs +116 -0
  22. package/dist/message-bubble.d.cts +38 -0
  23. package/dist/message-bubble.d.mts +38 -0
  24. package/dist/message-bubble.mjs +114 -0
  25. package/dist/message-input-CkaL6fb4.mjs +173 -0
  26. package/dist/message-input-DcEzHQ9t.cjs +191 -0
  27. package/dist/message-input.cjs +6 -0
  28. package/dist/message-input.d.cts +51 -0
  29. package/dist/message-input.d.mts +51 -0
  30. package/dist/message-input.mjs +5 -0
  31. package/dist/message-view.cjs +273 -0
  32. package/dist/message-view.d.cts +109 -0
  33. package/dist/message-view.d.mts +109 -0
  34. package/dist/message-view.mjs +266 -0
  35. package/dist/message.cjs +50 -0
  36. package/dist/message.d.cts +40 -0
  37. package/dist/message.d.mts +40 -0
  38. package/dist/message.mjs +43 -0
  39. package/dist/tailwind.css +33 -0
  40. package/dist/utils-Bp9IahGG.cjs +91 -0
  41. package/dist/utils.cjs +5 -0
  42. package/dist/utils.d.cts +20 -0
  43. package/dist/utils.d.mts +20 -0
  44. package/dist/utils.mjs +45 -0
  45. package/dist/whatsapp-dashboard.cjs +64 -0
  46. package/dist/whatsapp-dashboard.d.cts +33 -0
  47. package/dist/whatsapp-dashboard.d.mts +33 -0
  48. package/dist/whatsapp-dashboard.mjs +60 -0
  49. package/dist/wpp-bg.webp +0 -0
  50. package/package.json +1 -1
@@ -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 };
@@ -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 };