@cossistant/react 0.0.26 → 0.0.29
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/README.md +1 -1
- package/api.d.ts +1 -1
- package/api.d.ts.map +1 -1
- package/checks.d.ts +1 -1
- package/checks.d.ts.map +1 -1
- package/coerce.d.ts +1 -1
- package/coerce.d.ts.map +1 -1
- package/conversation.d.ts +6 -3
- package/conversation.d.ts.map +1 -1
- package/core.d.ts +1 -1
- package/core.d.ts.map +1 -1
- package/errors.d.ts +12 -3
- package/errors.d.ts.map +1 -1
- package/errors2.d.ts +1 -1
- package/errors2.d.ts.map +1 -1
- package/hooks/index.d.ts +3 -2
- package/hooks/index.js +6 -5
- package/hooks/private/store/use-website-store.js +2 -1
- package/hooks/private/store/use-website-store.js.map +1 -1
- package/hooks/private/use-client-query.d.ts +6 -0
- package/hooks/private/use-client-query.d.ts.map +1 -1
- package/hooks/private/use-client-query.js +26 -3
- package/hooks/private/use-client-query.js.map +1 -1
- package/hooks/private/use-grouped-messages.d.ts +8 -5
- package/hooks/private/use-grouped-messages.d.ts.map +1 -1
- package/hooks/private/use-grouped-messages.js +44 -11
- package/hooks/private/use-grouped-messages.js.map +1 -1
- package/hooks/private/use-multimodal-input.d.ts.map +1 -1
- package/hooks/private/use-multimodal-input.js +7 -5
- package/hooks/private/use-multimodal-input.js.map +1 -1
- package/hooks/private/use-visitor-typing-reporter.d.ts +18 -1
- package/hooks/private/use-visitor-typing-reporter.d.ts.map +1 -1
- package/hooks/private/use-visitor-typing-reporter.js +34 -4
- package/hooks/private/use-visitor-typing-reporter.js.map +1 -1
- package/hooks/use-conversation-page.d.ts +1 -0
- package/hooks/use-conversation-page.d.ts.map +1 -1
- package/hooks/use-conversation-page.js +6 -1
- package/hooks/use-conversation-page.js.map +1 -1
- package/hooks/use-conversation-preview.d.ts +2 -1
- package/hooks/use-conversation-preview.d.ts.map +1 -1
- package/hooks/use-conversation-preview.js +1 -1
- package/hooks/use-conversation-preview.js.map +1 -1
- package/hooks/use-conversation-seen.js +1 -1
- package/hooks/use-conversation-seen.js.map +1 -1
- package/hooks/use-conversation-timeline-items.js +2 -1
- package/hooks/use-conversation-timeline-items.js.map +1 -1
- package/hooks/use-conversation-timeline.d.ts.map +1 -1
- package/hooks/use-conversation-timeline.js +1 -3
- package/hooks/use-conversation-timeline.js.map +1 -1
- package/hooks/use-conversation.js +2 -1
- package/hooks/use-conversation.js.map +1 -1
- package/hooks/use-conversations.js +1 -0
- package/hooks/use-conversations.js.map +1 -1
- package/hooks/use-create-conversation.d.ts.map +1 -1
- package/hooks/use-file-upload.d.ts +55 -0
- package/hooks/use-file-upload.d.ts.map +1 -0
- package/hooks/use-file-upload.js +100 -0
- package/hooks/use-file-upload.js.map +1 -0
- package/hooks/use-message-composer.d.ts +11 -0
- package/hooks/use-message-composer.d.ts.map +1 -1
- package/hooks/use-message-composer.js +7 -3
- package/hooks/use-message-composer.js.map +1 -1
- package/hooks/use-send-message.d.ts +1 -0
- package/hooks/use-send-message.d.ts.map +1 -1
- package/hooks/use-send-message.js +63 -11
- package/hooks/use-send-message.js.map +1 -1
- package/index.d.ts +7 -4
- package/index.js +13 -10
- package/json-schema.d.ts +70 -0
- package/json-schema.d.ts.map +1 -0
- package/package.json +4 -3
- package/parse.d.ts +1 -1
- package/parse.d.ts.map +1 -1
- package/primitives/avatar/fallback.d.ts.map +1 -1
- package/primitives/avatar/fallback.js +1 -1
- package/primitives/avatar/fallback.js.map +1 -1
- package/primitives/conversation-timeline.d.ts.map +1 -1
- package/primitives/conversation-timeline.js +10 -5
- package/primitives/conversation-timeline.js.map +1 -1
- package/primitives/day-separator.d.ts +76 -0
- package/primitives/day-separator.d.ts.map +1 -0
- package/primitives/day-separator.js +111 -0
- package/primitives/day-separator.js.map +1 -0
- package/primitives/index.d.ts +5 -3
- package/primitives/index.js +17 -5
- package/primitives/index.parts.d.ts +4 -2
- package/primitives/index.parts.js +5 -3
- package/primitives/timeline-item-attachments.d.ts +100 -0
- package/primitives/timeline-item-attachments.d.ts.map +1 -0
- package/primitives/timeline-item-attachments.js +151 -0
- package/primitives/timeline-item-attachments.js.map +1 -0
- package/primitives/timeline-item-group.d.ts.map +1 -1
- package/primitives/timeline-item-group.js +1 -1
- package/primitives/timeline-item-group.js.map +1 -1
- package/primitives/timeline-item.js +1 -1
- package/primitives/timeline-item.js.map +1 -1
- package/primitives/trigger.d.ts +91 -0
- package/primitives/trigger.d.ts.map +1 -0
- package/primitives/trigger.js +74 -0
- package/primitives/trigger.js.map +1 -0
- package/primitives/window.d.ts +22 -1
- package/primitives/window.d.ts.map +1 -1
- package/primitives/window.js +91 -5
- package/primitives/window.js.map +1 -1
- package/provider.d.ts.map +1 -1
- package/provider.js +8 -3
- package/provider.js.map +1 -1
- package/realtime/index.js +1 -1
- package/realtime/provider.js +1 -1
- package/realtime/support-provider.js +5 -1
- package/realtime/support-provider.js.map +1 -1
- package/realtime-events.d.ts +165 -2
- package/realtime-events.d.ts.map +1 -1
- package/registries.d.ts +1 -1
- package/registries.d.ts.map +1 -1
- package/schemas.d.ts +305 -7
- package/schemas.d.ts.map +1 -1
- package/schemas2.d.ts +29 -4
- package/schemas2.d.ts.map +1 -1
- package/schemas3.d.ts +2 -1
- package/schemas3.d.ts.map +1 -1
- package/standard-schema.d.ts +83 -21
- package/standard-schema.d.ts.map +1 -1
- package/support/components/button.d.ts +1 -1
- package/support/components/content.d.ts +30 -0
- package/support/components/content.d.ts.map +1 -0
- package/support/components/content.js +282 -0
- package/support/components/content.js.map +1 -0
- package/support/components/conversation-button-link.js +1 -1
- package/support/components/conversation-timeline.d.ts +5 -0
- package/support/components/conversation-timeline.d.ts.map +1 -1
- package/support/components/conversation-timeline.js +25 -5
- package/support/components/conversation-timeline.js.map +1 -1
- package/support/components/header.js +1 -1
- package/support/components/image-lightbox.d.ts +49 -0
- package/support/components/image-lightbox.d.ts.map +1 -0
- package/support/components/image-lightbox.js +142 -0
- package/support/components/image-lightbox.js.map +1 -0
- package/support/components/index.d.ts +5 -4
- package/support/components/index.js +4 -4
- package/support/components/multimodal-input.d.ts +4 -1
- package/support/components/multimodal-input.d.ts.map +1 -1
- package/support/components/multimodal-input.js +71 -45
- package/support/components/multimodal-input.js.map +1 -1
- package/support/components/navigation-tab.js +1 -1
- package/support/components/root.d.ts +23 -0
- package/support/components/root.d.ts.map +1 -0
- package/support/components/root.js +36 -0
- package/support/components/root.js.map +1 -0
- package/support/components/timeline-message-item.d.ts.map +1 -1
- package/support/components/timeline-message-item.js +82 -18
- package/support/components/timeline-message-item.js.map +1 -1
- package/support/components/trigger.d.ts +14 -0
- package/support/components/trigger.d.ts.map +1 -0
- package/support/components/{bubble.js → trigger.js} +16 -12
- package/support/components/trigger.js.map +1 -0
- package/support/components/typing-indicator.d.ts.map +1 -1
- package/support/components/typing-indicator.js +1 -0
- package/support/components/typing-indicator.js.map +1 -1
- package/support/context/controlled-state.d.ts +46 -0
- package/support/context/controlled-state.d.ts.map +1 -0
- package/support/context/controlled-state.js +34 -0
- package/support/context/controlled-state.js.map +1 -0
- package/support/context/events.d.ts +103 -0
- package/support/context/events.d.ts.map +1 -0
- package/support/context/events.js +139 -0
- package/support/context/events.js.map +1 -0
- package/support/context/handle.d.ts +90 -0
- package/support/context/handle.d.ts.map +1 -0
- package/support/context/handle.js +79 -0
- package/support/context/handle.js.map +1 -0
- package/support/context/positioning.d.ts +17 -0
- package/support/context/positioning.d.ts.map +1 -0
- package/support/context/positioning.js +26 -0
- package/support/context/positioning.js.map +1 -0
- package/support/context/slots.d.ts +85 -0
- package/support/context/slots.d.ts.map +1 -0
- package/support/context/slots.js +115 -0
- package/support/context/slots.js.map +1 -0
- package/support/context/websocket.d.ts +8 -1
- package/support/context/websocket.d.ts.map +1 -1
- package/support/context/websocket.js +8 -1
- package/support/context/websocket.js.map +1 -1
- package/support/index.d.ts +239 -54
- package/support/index.d.ts.map +1 -1
- package/support/index.js +254 -33
- package/support/index.js.map +1 -1
- package/support/pages/articles.d.ts.map +1 -1
- package/support/pages/articles.js +3 -4
- package/support/pages/articles.js.map +1 -1
- package/support/pages/conversation-history.js +2 -2
- package/support/pages/conversation.js +6 -5
- package/support/pages/conversation.js.map +1 -1
- package/support/pages/home.js +2 -2
- package/support/router.d.ts +52 -12
- package/support/router.d.ts.map +1 -1
- package/support/router.js +78 -30
- package/support/router.js.map +1 -1
- package/support/store/index.d.ts +2 -2
- package/support/store/support-store.d.ts +26 -20
- package/support/store/support-store.d.ts.map +1 -1
- package/support/store/support-store.js +47 -6
- package/support/store/support-store.js.map +1 -1
- package/support/{support-D2EgfIts.css → support-C7Xaw-N6.css} +1 -2
- package/support/support-C7Xaw-N6.css.map +1 -0
- package/support/text/index.d.ts +1 -1
- package/support/text/index.d.ts.map +1 -1
- package/support/text/index.js.map +1 -1
- package/support/types.d.ts +75 -12
- package/support/types.d.ts.map +1 -1
- package/support.css +2 -2
- package/tailwind.css +0 -1
- package/timeline-item.d.ts +68 -2
- package/timeline-item.d.ts.map +1 -1
- package/to-json-schema.d.ts +96 -0
- package/to-json-schema.d.ts.map +1 -0
- package/util.d.ts +6 -2
- package/util.d.ts.map +1 -1
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/merge-refs.d.ts +30 -0
- package/utils/merge-refs.d.ts.map +1 -0
- package/utils/merge-refs.js +46 -0
- package/utils/merge-refs.js.map +1 -0
- package/utils/use-render-element.d.ts.map +1 -1
- package/utils/use-render-element.js +36 -8
- package/utils/use-render-element.js.map +1 -1
- package/versions.d.ts +2 -2
- package/versions.d.ts.map +1 -1
- package/zod-extensions.d.ts +1 -1
- package/zod-extensions.d.ts.map +1 -1
- package/primitives/bubble.d.ts +0 -38
- package/primitives/bubble.d.ts.map +0 -1
- package/primitives/bubble.js +0 -57
- package/primitives/bubble.js.map +0 -1
- package/support/components/bubble.d.ts +0 -10
- package/support/components/bubble.d.ts.map +0 -1
- package/support/components/bubble.js.map +0 -1
- package/support/components/container.d.ts +0 -13
- package/support/components/container.d.ts.map +0 -1
- package/support/components/container.js +0 -109
- package/support/components/container.js.map +0 -1
- package/support/components/support-content.d.ts +0 -22
- package/support/components/support-content.d.ts.map +0 -1
- package/support/components/support-content.js +0 -48
- package/support/components/support-content.js.map +0 -1
- package/support/support-D2EgfIts.css.map +0 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import { cn } from "../utils/index.js";
|
|
5
|
+
import { TriggerRefProvider } from "../context/positioning.js";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
import { motion } from "motion/react";
|
|
8
|
+
|
|
9
|
+
//#region src/support/components/root.tsx
|
|
10
|
+
/**
|
|
11
|
+
* Root wrapper component that provides the positioning context.
|
|
12
|
+
* Contains the trigger and content as siblings.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <Support.Root>
|
|
16
|
+
* <Support.Trigger>Help</Support.Trigger>
|
|
17
|
+
* <Support.Content>
|
|
18
|
+
* <Support.Router />
|
|
19
|
+
* </Support.Content>
|
|
20
|
+
* </Support.Root>
|
|
21
|
+
*/
|
|
22
|
+
const Root = ({ className, children }) => /* @__PURE__ */ jsx(TriggerRefProvider, { children: /* @__PURE__ */ jsx(motion.div, {
|
|
23
|
+
animate: { opacity: 1 },
|
|
24
|
+
className: cn("cossistant relative", className),
|
|
25
|
+
initial: { opacity: 0 },
|
|
26
|
+
layout: "position",
|
|
27
|
+
transition: {
|
|
28
|
+
default: { ease: "anticipate" },
|
|
29
|
+
layout: { duration: .3 }
|
|
30
|
+
},
|
|
31
|
+
children
|
|
32
|
+
}) });
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { Root };
|
|
36
|
+
//# sourceMappingURL=root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root.js","names":["Root: React.FC<RootProps>"],"sources":["../../../src/support/components/root.tsx"],"sourcesContent":["\"use client\";\n\nimport { motion } from \"motion/react\";\nimport type * as React from \"react\";\nimport { TriggerRefProvider } from \"../context/positioning\";\nimport { cn } from \"../utils\";\n\nexport type RootProps = {\n\tclassName?: string;\n\tchildren: React.ReactNode;\n};\n\n/**\n * Root wrapper component that provides the positioning context.\n * Contains the trigger and content as siblings.\n *\n * @example\n * <Support.Root>\n * <Support.Trigger>Help</Support.Trigger>\n * <Support.Content>\n * <Support.Router />\n * </Support.Content>\n * </Support.Root>\n */\nexport const Root: React.FC<RootProps> = ({ className, children }) => (\n\t<TriggerRefProvider>\n\t\t<motion.div\n\t\t\tanimate={{ opacity: 1 }}\n\t\t\tclassName={cn(\"cossistant relative\", className)}\n\t\t\tinitial={{ opacity: 0 }}\n\t\t\tlayout=\"position\"\n\t\t\ttransition={{\n\t\t\t\tdefault: { ease: \"anticipate\" },\n\t\t\t\tlayout: { duration: 0.3 },\n\t\t\t}}\n\t\t>\n\t\t\t{children}\n\t\t</motion.div>\n\t</TriggerRefProvider>\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwBA,MAAaA,QAA6B,EAAE,WAAW,eACtD,oBAAC,gCACA,oBAAC,OAAO;CACP,SAAS,EAAE,SAAS,GAAG;CACvB,WAAW,GAAG,uBAAuB,UAAU;CAC/C,SAAS,EAAE,SAAS,GAAG;CACvB,QAAO;CACP,YAAY;EACX,SAAS,EAAE,MAAM,cAAc;EAC/B,QAAQ,EAAE,UAAU,IAAK;EACzB;CAEA;EACW,GACO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline-message-item.d.ts","names":[],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"timeline-message-item.d.ts","names":[],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":[],"mappings":";;;;KAkBY,wBAAA;QACL;EADK,MAAA,CAAA,EAAA,OAAA;EAUI,cAAA,CAAA,EAAA,OAAmB;CAClC;;;;;AAG+C,iBAJhC,mBAAA,CAIgC;EAAA,IAAA;EAAA,MAAA;EAAA;AAAA,CAAA,EAA7C,wBAA6C,CAAA,EAAlB,KAAA,CAAM,YAAY"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { cn } from "../utils/index.js";
|
|
2
2
|
import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "../../primitives/timeline-item.js";
|
|
3
|
+
import { extractFileParts, extractImageParts } from "../../primitives/timeline-item-attachments.js";
|
|
4
|
+
import icons_default from "./icons.js";
|
|
3
5
|
import { useSupportText } from "../text/index.js";
|
|
6
|
+
import { ImageLightbox } from "./image-lightbox.js";
|
|
7
|
+
import { useState } from "react";
|
|
8
|
+
import { formatFileSize } from "@cossistant/core";
|
|
4
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
10
|
|
|
6
11
|
//#region src/support/components/timeline-message-item.tsx
|
|
@@ -10,7 +15,17 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
10
15
|
*/
|
|
11
16
|
function TimelineMessageItem({ item, isLast = false, isSentByViewer = false }) {
|
|
12
17
|
const text = useSupportText();
|
|
13
|
-
|
|
18
|
+
const [lightboxOpen, setLightboxOpen] = useState(false);
|
|
19
|
+
const [lightboxIndex, setLightboxIndex] = useState(0);
|
|
20
|
+
const images = extractImageParts(item.parts);
|
|
21
|
+
const files = extractFileParts(item.parts);
|
|
22
|
+
const hasAttachments = images.length > 0 || files.length > 0;
|
|
23
|
+
const hasText = item.text && item.text.trim().length > 0;
|
|
24
|
+
const openLightbox = (index) => {
|
|
25
|
+
setLightboxIndex(index);
|
|
26
|
+
setLightboxOpen(true);
|
|
27
|
+
};
|
|
28
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(TimelineItem, {
|
|
14
29
|
item,
|
|
15
30
|
children: ({ isAI, timestamp }) => {
|
|
16
31
|
const isSentByViewerFinal = isSentByViewer;
|
|
@@ -18,27 +33,76 @@ function TimelineMessageItem({ item, isLast = false, isSentByViewer = false }) {
|
|
|
18
33
|
className: cn("flex w-full gap-2", isSentByViewerFinal && "flex-row-reverse", !isSentByViewerFinal && "flex-row"),
|
|
19
34
|
children: /* @__PURE__ */ jsxs("div", {
|
|
20
35
|
className: cn("flex w-full min-w-0 flex-1 flex-col gap-1", isSentByViewerFinal && "items-end"),
|
|
21
|
-
children: [
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
36
|
+
children: [
|
|
37
|
+
hasText && /* @__PURE__ */ jsx(TimelineItemContent, {
|
|
38
|
+
className: cn("block min-w-0 max-w-[300px] whitespace-pre-wrap break-words rounded-lg px-3.5 py-2.5 text-sm", {
|
|
39
|
+
"bg-co-background-300 text-co-foreground dark:bg-co-background-600": !isSentByViewerFinal,
|
|
40
|
+
"bg-co-primary text-co-primary-foreground": isSentByViewerFinal,
|
|
41
|
+
"rounded-br-sm": isLast && isSentByViewerFinal && !hasAttachments,
|
|
42
|
+
"rounded-bl-sm": isLast && !isSentByViewerFinal && !hasAttachments
|
|
43
|
+
}),
|
|
44
|
+
renderMarkdown: true,
|
|
45
|
+
text: item.text
|
|
27
46
|
}),
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
images.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
48
|
+
className: cn("flex flex-wrap gap-2", isSentByViewerFinal && "justify-end"),
|
|
49
|
+
children: images.map((image, index) => /* @__PURE__ */ jsx("button", {
|
|
50
|
+
className: "group relative overflow-hidden rounded-lg focus:outline-none focus:ring-2 focus:ring-co-primary/50",
|
|
51
|
+
onClick: () => openLightbox(index),
|
|
52
|
+
type: "button",
|
|
53
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
54
|
+
alt: image.fileName || `Image ${index + 1}`,
|
|
55
|
+
className: "max-h-[150px] max-w-[200px] cursor-pointer rounded-lg object-cover transition-transform group-hover:scale-105",
|
|
56
|
+
loading: "lazy",
|
|
57
|
+
src: image.url
|
|
58
|
+
})
|
|
59
|
+
}, image.url))
|
|
60
|
+
}),
|
|
61
|
+
files.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
62
|
+
className: "flex flex-col gap-1",
|
|
63
|
+
children: files.map((file) => /* @__PURE__ */ jsxs("a", {
|
|
64
|
+
className: cn("flex items-center gap-2 rounded-lg px-3 py-2 text-xs transition-colors", {
|
|
65
|
+
"bg-co-background-300 text-co-foreground hover:bg-co-background-400 dark:bg-co-background-600 dark:hover:bg-co-background-500": !isSentByViewerFinal,
|
|
66
|
+
"bg-co-primary/80 text-co-primary-foreground hover:bg-co-primary": isSentByViewerFinal
|
|
67
|
+
}),
|
|
68
|
+
download: file.fileName,
|
|
69
|
+
href: file.url,
|
|
70
|
+
rel: "noopener noreferrer",
|
|
71
|
+
target: "_blank",
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ jsx(icons_default, {
|
|
74
|
+
className: "h-4 w-4 shrink-0",
|
|
75
|
+
name: "file"
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ jsx("span", {
|
|
78
|
+
className: "flex-1 truncate font-medium",
|
|
79
|
+
children: file.fileName || "Download file"
|
|
80
|
+
}),
|
|
81
|
+
file.size && /* @__PURE__ */ jsx("span", {
|
|
82
|
+
className: "text-co-muted-foreground opacity-70",
|
|
83
|
+
children: formatFileSize(file.size)
|
|
84
|
+
})
|
|
85
|
+
]
|
|
86
|
+
}, file.url))
|
|
87
|
+
}),
|
|
88
|
+
isLast && /* @__PURE__ */ jsx(TimelineItemTimestamp, {
|
|
89
|
+
className: "px-1 text-co-muted-foreground text-xs",
|
|
90
|
+
timestamp,
|
|
91
|
+
children: () => /* @__PURE__ */ jsxs(Fragment, { children: [timestamp.toLocaleTimeString([], {
|
|
92
|
+
hour: "2-digit",
|
|
93
|
+
minute: "2-digit"
|
|
94
|
+
}), isAI && ` ${text("component.message.timestamp.aiIndicator")}`] })
|
|
95
|
+
})
|
|
96
|
+
]
|
|
38
97
|
})
|
|
39
98
|
});
|
|
40
99
|
}
|
|
41
|
-
})
|
|
100
|
+
}), images.length > 0 && /* @__PURE__ */ jsx(ImageLightbox, {
|
|
101
|
+
images,
|
|
102
|
+
initialIndex: lightboxIndex,
|
|
103
|
+
isOpen: lightboxOpen,
|
|
104
|
+
onClose: () => setLightboxOpen(false)
|
|
105
|
+
})] });
|
|
42
106
|
}
|
|
43
107
|
|
|
44
108
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline-message-item.js","names":["PrimitiveTimelineItem"],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":["import type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport {\n\tTimelineItem as PrimitiveTimelineItem,\n\tTimelineItemContent,\n\tTimelineItemTimestamp,\n} from \"../../primitives/timeline-item\";\nimport { useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\n\nexport type TimelineMessageItemProps = {\n\titem: TimelineItem;\n\tisLast?: boolean;\n\tisSentByViewer?: boolean;\n};\n\n/**\n * Message bubble renderer that adapts layout depending on whether the visitor\n * or an agent sent the message.\n */\nexport function TimelineMessageItem({\n\titem,\n\tisLast = false,\n\tisSentByViewer = false,\n}: TimelineMessageItemProps): React.ReactElement {\n\tconst text = useSupportText();\n\treturn (\n\t\t<PrimitiveTimelineItem item={item}>\n\t\t\t{({ isAI, timestamp }) => {\n\t\t\t\t// isSentByViewer defaults to false, meaning messages are treated as received\n\t\t\t\t// (left side with background) unless explicitly marked as sent by viewer\n\t\t\t\tconst isSentByViewerFinal = isSentByViewer;\n\n\t\t\t\treturn (\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"flex w-full gap-2\",\n\t\t\t\t\t\t\tisSentByViewerFinal && \"flex-row-reverse\",\n\t\t\t\t\t\t\t!isSentByViewerFinal && \"flex-row\"\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"flex w-full min-w-0 flex-1 flex-col gap-1\",\n\t\t\t\t\t\t\t\tisSentByViewerFinal && \"items-end\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<TimelineItemContent\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\"block min-w-0 max-w-[300px] whitespace-pre-wrap break-words rounded-lg px-3.5 py-2.5 text-sm\",\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground dark:bg-co-background-600\":\n\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\"bg-co-primary text-co-primary-foreground\":\n\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\"rounded-br-sm\"
|
|
1
|
+
{"version":3,"file":"timeline-message-item.js","names":["PrimitiveTimelineItem","Icon"],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":["import { formatFileSize } from \"@cossistant/core\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport { useState } from \"react\";\nimport {\n\tTimelineItem as PrimitiveTimelineItem,\n\tTimelineItemContent,\n\tTimelineItemTimestamp,\n} from \"../../primitives/timeline-item\";\nimport {\n\textractFileParts,\n\textractImageParts,\n} from \"../../primitives/timeline-item-attachments\";\nimport { useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\nimport { ImageLightbox } from \"./image-lightbox\";\n\nexport type TimelineMessageItemProps = {\n\titem: TimelineItem;\n\tisLast?: boolean;\n\tisSentByViewer?: boolean;\n};\n\n/**\n * Message bubble renderer that adapts layout depending on whether the visitor\n * or an agent sent the message.\n */\nexport function TimelineMessageItem({\n\titem,\n\tisLast = false,\n\tisSentByViewer = false,\n}: TimelineMessageItemProps): React.ReactElement {\n\tconst text = useSupportText();\n\tconst [lightboxOpen, setLightboxOpen] = useState(false);\n\tconst [lightboxIndex, setLightboxIndex] = useState(0);\n\n\t// Extract image and file parts\n\tconst images = extractImageParts(item.parts);\n\tconst files = extractFileParts(item.parts);\n\tconst hasAttachments = images.length > 0 || files.length > 0;\n\tconst hasText = item.text && item.text.trim().length > 0;\n\n\tconst openLightbox = (index: number) => {\n\t\tsetLightboxIndex(index);\n\t\tsetLightboxOpen(true);\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<PrimitiveTimelineItem item={item}>\n\t\t\t\t{({ isAI, timestamp }) => {\n\t\t\t\t\t// isSentByViewer defaults to false, meaning messages are treated as received\n\t\t\t\t\t// (left side with background) unless explicitly marked as sent by viewer\n\t\t\t\t\tconst isSentByViewerFinal = isSentByViewer;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"flex w-full gap-2\",\n\t\t\t\t\t\t\t\tisSentByViewerFinal && \"flex-row-reverse\",\n\t\t\t\t\t\t\t\t!isSentByViewerFinal && \"flex-row\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\"flex w-full min-w-0 flex-1 flex-col gap-1\",\n\t\t\t\t\t\t\t\t\tisSentByViewerFinal && \"items-end\"\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{/* Text content */}\n\t\t\t\t\t\t\t\t{hasText && (\n\t\t\t\t\t\t\t\t\t<TimelineItemContent\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"block min-w-0 max-w-[300px] whitespace-pre-wrap break-words rounded-lg px-3.5 py-2.5 text-sm\",\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground dark:bg-co-background-600\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-primary text-co-primary-foreground\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\"rounded-br-sm\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisLast && isSentByViewerFinal && !hasAttachments,\n\t\t\t\t\t\t\t\t\t\t\t\t\"rounded-bl-sm\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisLast && !isSentByViewerFinal && !hasAttachments,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\trenderMarkdown\n\t\t\t\t\t\t\t\t\t\ttext={item.text}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* Image attachments */}\n\t\t\t\t\t\t\t\t{images.length > 0 && (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"flex flex-wrap gap-2\",\n\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal && \"justify-end\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{images.map((image, index) => (\n\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"group relative overflow-hidden rounded-lg focus:outline-none focus:ring-2 focus:ring-co-primary/50\"\n\t\t\t\t\t\t\t\t\t\t\t\tkey={image.url}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => openLightbox(index)}\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{/* biome-ignore lint/performance/noImgElement: React package, not Next.js specific */}\n\t\t\t\t\t\t\t\t\t\t\t\t{/* biome-ignore lint/nursery/useImageSize: Dynamic image dimensions not known at render time */}\n\t\t\t\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\t\t\t\talt={image.fileName || `Image ${index + 1}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"max-h-[150px] max-w-[200px] cursor-pointer rounded-lg object-cover transition-transform group-hover:scale-105\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tsrc={image.url}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* File attachments */}\n\t\t\t\t\t\t\t\t{files.length > 0 && (\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t\t\t\t\t{files.map((file) => (\n\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"flex items-center gap-2 rounded-lg px-3 py-2 text-xs transition-colors\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground hover:bg-co-background-400 dark:bg-co-background-600 dark:hover:bg-co-background-500\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-primary/80 text-co-primary-foreground hover:bg-co-primary\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tdownload={file.fileName}\n\t\t\t\t\t\t\t\t\t\t\t\thref={file.url}\n\t\t\t\t\t\t\t\t\t\t\t\tkey={file.url}\n\t\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon className=\"h-4 w-4 shrink-0\" name=\"file\" />\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex-1 truncate font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{file.fileName || \"Download file\"}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t{file.size && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-co-muted-foreground opacity-70\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(file.size)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{isLast && (\n\t\t\t\t\t\t\t\t\t<TimelineItemTimestamp\n\t\t\t\t\t\t\t\t\t\tclassName=\"px-1 text-co-muted-foreground text-xs\"\n\t\t\t\t\t\t\t\t\t\ttimestamp={timestamp}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{() => (\n\t\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t\t{timestamp.toLocaleTimeString([], {\n\t\t\t\t\t\t\t\t\t\t\t\t\thour: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tminute: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t{isAI &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t` ${text(\"component.message.timestamp.aiIndicator\")}`}\n\t\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</TimelineItemTimestamp>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t}}\n\t\t\t</PrimitiveTimelineItem>\n\n\t\t\t{/* Lightbox for images */}\n\t\t\t{images.length > 0 && (\n\t\t\t\t<ImageLightbox\n\t\t\t\t\timages={images}\n\t\t\t\t\tinitialIndex={lightboxIndex}\n\t\t\t\t\tisOpen={lightboxOpen}\n\t\t\t\t\tonClose={() => setLightboxOpen(false)}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,SAAgB,oBAAoB,EACnC,MACA,SAAS,OACT,iBAAiB,SAC+B;CAChD,MAAM,OAAO,gBAAgB;CAC7B,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CACvD,MAAM,CAAC,eAAe,oBAAoB,SAAS,EAAE;CAGrD,MAAM,SAAS,kBAAkB,KAAK,MAAM;CAC5C,MAAM,QAAQ,iBAAiB,KAAK,MAAM;CAC1C,MAAM,iBAAiB,OAAO,SAAS,KAAK,MAAM,SAAS;CAC3D,MAAM,UAAU,KAAK,QAAQ,KAAK,KAAK,MAAM,CAAC,SAAS;CAEvD,MAAM,gBAAgB,UAAkB;AACvC,mBAAiB,MAAM;AACvB,kBAAgB,KAAK;;AAGtB,QACC,4CACC,oBAACA;EAA4B;aAC1B,EAAE,MAAM,gBAAgB;GAGzB,MAAM,sBAAsB;AAE5B,UACC,oBAAC;IACA,WAAW,GACV,qBACA,uBAAuB,oBACvB,CAAC,uBAAuB,WACxB;cAED,qBAAC;KACA,WAAW,GACV,6CACA,uBAAuB,YACvB;;MAGA,WACA,oBAAC;OACA,WAAW,GACV,gGACA;QACC,qEACC,CAAC;QACF,4CACC;QACD,iBACC,UAAU,uBAAuB,CAAC;QACnC,iBACC,UAAU,CAAC,uBAAuB,CAAC;QACpC,CACD;OACD;OACA,MAAM,KAAK;QACV;MAIF,OAAO,SAAS,KAChB,oBAAC;OACA,WAAW,GACV,wBACA,uBAAuB,cACvB;iBAEA,OAAO,KAAK,OAAO,UACnB,oBAAC;QACA,WAAU;QAEV,eAAe,aAAa,MAAM;QAClC,MAAK;kBAIL,oBAAC;SACA,KAAK,MAAM,YAAY,SAAS,QAAQ;SACxC,WAAU;SACV,SAAQ;SACR,KAAK,MAAM;UACV;UAXG,MAAM,IAYH,CACR;QACG;MAIN,MAAM,SAAS,KACf,oBAAC;OAAI,WAAU;iBACb,MAAM,KAAK,SACX,qBAAC;QACA,WAAW,GACV,0EACA;SACC,gIACC,CAAC;SACF,mEACC;SACD,CACD;QACD,UAAU,KAAK;QACf,MAAM,KAAK;QAEX,KAAI;QACJ,QAAO;;SAEP,oBAACC;UAAK,WAAU;UAAmB,MAAK;WAAS;SACjD,oBAAC;UAAK,WAAU;oBACd,KAAK,YAAY;WACZ;SACN,KAAK,QACL,oBAAC;UAAK,WAAU;oBACd,eAAe,KAAK,KAAK;WACpB;;UAXH,KAAK,IAaP,CACH;QACG;MAGN,UACA,oBAAC;OACA,WAAU;OACC;uBAGV,4CACE,UAAU,mBAAmB,EAAE,EAAE;QACjC,MAAM;QACN,QAAQ;QACR,CAAC,EACD,QACA,IAAI,KAAK,0CAA0C,MAClD;QAEmB;;MAEpB;KACD;;GAGe,EAGvB,OAAO,SAAS,KAChB,oBAAC;EACQ;EACR,cAAc;EACd,QAAQ;EACR,eAAe,gBAAgB,MAAM;GACpC,IAED"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/support/components/trigger.d.ts
|
|
4
|
+
type DefaultTriggerProps = {
|
|
5
|
+
className?: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Default styled trigger button.
|
|
9
|
+
* Used internally when no custom trigger is provided.
|
|
10
|
+
*/
|
|
11
|
+
declare const DefaultTrigger: React$1.FC<DefaultTriggerProps>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { DefaultTrigger, DefaultTriggerProps };
|
|
14
|
+
//# sourceMappingURL=trigger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trigger.d.ts","names":[],"sources":["../../../src/support/components/trigger.tsx"],"sourcesContent":[],"mappings":";;;KA2HY,mBAAA;;AAAZ,CAAA;AAQA;;;;cAAa,gBAAgB,OAAA,CAAM,GAAG"}
|
|
@@ -3,26 +3,26 @@
|
|
|
3
3
|
|
|
4
4
|
import { cn } from "../utils/index.js";
|
|
5
5
|
import { BouncingDots } from "./typing-indicator.js";
|
|
6
|
-
import {
|
|
7
|
-
import icons_default from "./icons.js";
|
|
6
|
+
import { SupportTrigger } from "../../primitives/trigger.js";
|
|
8
7
|
import { useNewMessageSound } from "../../hooks/use-new-message-sound.js";
|
|
9
8
|
import { useTypingSound } from "../../hooks/use-typing-sound.js";
|
|
10
|
-
import
|
|
9
|
+
import icons_default from "./icons.js";
|
|
10
|
+
import * as React$1 from "react";
|
|
11
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
import { AnimatePresence, motion } from "motion/react";
|
|
13
13
|
|
|
14
|
-
//#region src/support/components/
|
|
15
|
-
const
|
|
14
|
+
//#region src/support/components/trigger.tsx
|
|
15
|
+
const TriggerContent = ({ isOpen, unreadCount, isTyping }) => {
|
|
16
16
|
const playNewMessageSound = useNewMessageSound({
|
|
17
17
|
volume: .7,
|
|
18
18
|
playbackRate: 1
|
|
19
19
|
});
|
|
20
|
-
const previousUnreadCountRef = useRef(0);
|
|
20
|
+
const previousUnreadCountRef = React$1.useRef(0);
|
|
21
21
|
useTypingSound(!isOpen && isTyping, {
|
|
22
22
|
volume: 1,
|
|
23
23
|
playbackRate: 1.3
|
|
24
24
|
});
|
|
25
|
-
useEffect(() => {
|
|
25
|
+
React$1.useEffect(() => {
|
|
26
26
|
if (unreadCount > previousUnreadCountRef.current) playNewMessageSound();
|
|
27
27
|
previousUnreadCountRef.current = unreadCount;
|
|
28
28
|
}, [unreadCount, playNewMessageSound]);
|
|
@@ -127,10 +127,14 @@ const BubbleContent = ({ isOpen, unreadCount, isTyping }) => {
|
|
|
127
127
|
}
|
|
128
128
|
})] });
|
|
129
129
|
};
|
|
130
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Default styled trigger button.
|
|
132
|
+
* Used internally when no custom trigger is provided.
|
|
133
|
+
*/
|
|
134
|
+
const DefaultTrigger = ({ className }) => /* @__PURE__ */ jsx(SupportTrigger, {
|
|
131
135
|
asChild: true,
|
|
132
136
|
children: ({ isOpen, unreadCount, isTyping }) => /* @__PURE__ */ jsx(motion.button, {
|
|
133
|
-
className: cn("relative flex size-14 cursor-pointer items-center justify-center rounded-full bg-co-primary text-co-primary-foreground transition-colors hover:bg-co-primary/90 data-[open=true]:bg-co-primary/90", className),
|
|
137
|
+
className: cn("relative z-[9999] flex size-14 cursor-pointer items-center justify-center rounded-full bg-co-primary text-co-primary-foreground transition-colors hover:bg-co-primary/90 data-[open=true]:bg-co-primary/90", className),
|
|
134
138
|
"data-open": isOpen,
|
|
135
139
|
transition: {
|
|
136
140
|
type: "spring",
|
|
@@ -139,7 +143,7 @@ const Bubble = ({ className }) => /* @__PURE__ */ jsx(SupportBubble, {
|
|
|
139
143
|
},
|
|
140
144
|
type: "button",
|
|
141
145
|
whileTap: { scale: .95 },
|
|
142
|
-
children: /* @__PURE__ */ jsx(
|
|
146
|
+
children: /* @__PURE__ */ jsx(TriggerContent, {
|
|
143
147
|
isOpen,
|
|
144
148
|
isTyping,
|
|
145
149
|
unreadCount
|
|
@@ -148,5 +152,5 @@ const Bubble = ({ className }) => /* @__PURE__ */ jsx(SupportBubble, {
|
|
|
148
152
|
});
|
|
149
153
|
|
|
150
154
|
//#endregion
|
|
151
|
-
export {
|
|
152
|
-
//# sourceMappingURL=
|
|
155
|
+
export { DefaultTrigger };
|
|
156
|
+
//# sourceMappingURL=trigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trigger.js","names":["TriggerContent: React.FC<TriggerContentProps>","React","Icon","DefaultTrigger: React.FC<DefaultTriggerProps>","Primitive.Trigger"],"sources":["../../../src/support/components/trigger.tsx"],"sourcesContent":["\"use client\";\n\nimport { AnimatePresence, motion } from \"motion/react\";\nimport * as React from \"react\";\nimport { useNewMessageSound } from \"../../hooks/use-new-message-sound\";\nimport { useTypingSound } from \"../../hooks/use-typing-sound\";\nimport * as Primitive from \"../../primitives\";\nimport type { TriggerRenderProps } from \"../types\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\nimport { BouncingDots } from \"./typing-indicator\";\n\ntype TriggerContentProps = {\n\tisOpen: boolean;\n\tunreadCount: number;\n\tisTyping: boolean;\n};\n\nconst TriggerContent: React.FC<TriggerContentProps> = ({\n\tisOpen,\n\tunreadCount,\n\tisTyping,\n}) => {\n\tconst playNewMessageSound = useNewMessageSound({\n\t\tvolume: 0.7,\n\t\tplaybackRate: 1.0,\n\t});\n\tconst previousUnreadCountRef = React.useRef(0);\n\n\tuseTypingSound(!isOpen && isTyping, {\n\t\tvolume: 1,\n\t\tplaybackRate: 1.3,\n\t});\n\n\tReact.useEffect(() => {\n\t\tif (unreadCount > previousUnreadCountRef.current) {\n\t\t\tplayNewMessageSound();\n\t\t}\n\t\tpreviousUnreadCountRef.current = unreadCount;\n\t}, [unreadCount, playNewMessageSound]);\n\n\treturn (\n\t\t<>\n\t\t\t<AnimatePresence mode=\"wait\">\n\t\t\t\t{isOpen ? (\n\t\t\t\t\t<motion.div\n\t\t\t\t\t\tanimate={{\n\t\t\t\t\t\t\tscale: 1,\n\t\t\t\t\t\t\trotate: 0,\n\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\ttransition: { duration: 0.2, ease: \"easeOut\" },\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName=\"flex items-center justify-center\"\n\t\t\t\t\t\texit={{\n\t\t\t\t\t\t\tscale: 0.9,\n\t\t\t\t\t\t\trotate: -45,\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\ttransition: { duration: 0.1, ease: \"easeIn\" },\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tinitial={{ scale: 0.9, rotate: 45, opacity: 0 }}\n\t\t\t\t\t\tkey=\"chevron\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon className=\"size-5\" name=\"chevron-down\" />\n\t\t\t\t\t</motion.div>\n\t\t\t\t) : isTyping ? (\n\t\t\t\t\t<motion.span\n\t\t\t\t\t\tanimate={{\n\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\tscale: 1,\n\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\tduration: 0.2,\n\t\t\t\t\t\t\t\tease: \"easeOut\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName=\"pointer-events-none flex items-center rounded-full text-co-primary\"\n\t\t\t\t\t\texit={{\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\tscale: 0.9,\n\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\tduration: 0.1,\n\t\t\t\t\t\t\t\tease: \"easeIn\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tinitial={{ opacity: 0, scale: 0.9 }}\n\t\t\t\t\t\tkey=\"typing-indicator\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<BouncingDots className=\"bg-co-primary-foreground\" />\n\t\t\t\t\t</motion.span>\n\t\t\t\t) : (\n\t\t\t\t\t<motion.div\n\t\t\t\t\t\tanimate={{\n\t\t\t\t\t\t\tscale: 1,\n\t\t\t\t\t\t\trotate: 0,\n\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\ttransition: { duration: 0.2, ease: \"easeOut\" },\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName=\"flex items-center justify-center\"\n\t\t\t\t\t\texit={{\n\t\t\t\t\t\t\tscale: 0.9,\n\t\t\t\t\t\t\trotate: 45,\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\ttransition: { duration: 0.1, ease: \"easeIn\" },\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tinitial={{ scale: 0.9, rotate: -45, opacity: 0 }}\n\t\t\t\t\t\tkey=\"chat\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon className=\"size-6.5\" name=\"chat\" variant=\"filled\" />\n\t\t\t\t\t</motion.div>\n\t\t\t\t)}\n\t\t\t</AnimatePresence>\n\n\t\t\t{unreadCount > 0 && (\n\t\t\t\t<motion.div\n\t\t\t\t\tanimate={{ scale: 1, opacity: 1 }}\n\t\t\t\t\tclassName=\"absolute top-0.5 right-0.5 flex size-2 items-center justify-center rounded-full bg-co-destructive font-medium text-[10px] text-co-destructive-foreground text-white text-xs\"\n\t\t\t\t\texit={{ scale: 0, opacity: 0 }}\n\t\t\t\t\tinitial={{ scale: 0, opacity: 0 }}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n};\n\nexport type DefaultTriggerProps = {\n\tclassName?: string;\n};\n\n/**\n * Default styled trigger button.\n * Used internally when no custom trigger is provided.\n */\nexport const DefaultTrigger: React.FC<DefaultTriggerProps> = ({\n\tclassName,\n}) => (\n\t<Primitive.Trigger asChild>\n\t\t{({ isOpen, unreadCount, isTyping }: TriggerRenderProps) => (\n\t\t\t<motion.button\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"relative z-[9999] flex size-14 cursor-pointer items-center justify-center rounded-full bg-co-primary text-co-primary-foreground transition-colors hover:bg-co-primary/90 data-[open=true]:bg-co-primary/90\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\tdata-open={isOpen}\n\t\t\t\ttransition={{\n\t\t\t\t\ttype: \"spring\",\n\t\t\t\t\tstiffness: 800,\n\t\t\t\t\tdamping: 17,\n\t\t\t\t}}\n\t\t\t\ttype=\"button\"\n\t\t\t\twhileTap={{ scale: 0.95 }}\n\t\t\t>\n\t\t\t\t<TriggerContent\n\t\t\t\t\tisOpen={isOpen}\n\t\t\t\t\tisTyping={isTyping}\n\t\t\t\t\tunreadCount={unreadCount}\n\t\t\t\t/>\n\t\t\t</motion.button>\n\t\t)}\n\t</Primitive.Trigger>\n);\n"],"mappings":";;;;;;;;;;;;;;AAkBA,MAAMA,kBAAiD,EACtD,QACA,aACA,eACK;CACL,MAAM,sBAAsB,mBAAmB;EAC9C,QAAQ;EACR,cAAc;EACd,CAAC;CACF,MAAM,yBAAyBC,QAAM,OAAO,EAAE;AAE9C,gBAAe,CAAC,UAAU,UAAU;EACnC,QAAQ;EACR,cAAc;EACd,CAAC;AAEF,SAAM,gBAAgB;AACrB,MAAI,cAAc,uBAAuB,QACxC,sBAAqB;AAEtB,yBAAuB,UAAU;IAC/B,CAAC,aAAa,oBAAoB,CAAC;AAEtC,QACC,4CACC,oBAAC;EAAgB,MAAK;YACpB,SACA,oBAAC,OAAO;GACP,SAAS;IACR,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;KAAE,UAAU;KAAK,MAAM;KAAW;IAC9C;GACD,WAAU;GACV,MAAM;IACL,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;KAAE,UAAU;KAAK,MAAM;KAAU;IAC7C;GACD,SAAS;IAAE,OAAO;IAAK,QAAQ;IAAI,SAAS;IAAG;aAG/C,oBAACC;IAAK,WAAU;IAAS,MAAK;KAAiB;KAF3C,UAGQ,GACV,WACH,oBAAC,OAAO;GACP,SAAS;IACR,SAAS;IACT,OAAO;IACP,YAAY;KACX,UAAU;KACV,MAAM;KACN;IACD;GACD,WAAU;GACV,MAAM;IACL,SAAS;IACT,OAAO;IACP,YAAY;KACX,UAAU;KACV,MAAM;KACN;IACD;GACD,SAAS;IAAE,SAAS;IAAG,OAAO;IAAK;aAGnC,oBAAC,gBAAa,WAAU,6BAA6B;KAFjD,mBAGS,GAEd,oBAAC,OAAO;GACP,SAAS;IACR,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;KAAE,UAAU;KAAK,MAAM;KAAW;IAC9C;GACD,WAAU;GACV,MAAM;IACL,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;KAAE,UAAU;KAAK,MAAM;KAAU;IAC7C;GACD,SAAS;IAAE,OAAO;IAAK,QAAQ;IAAK,SAAS;IAAG;aAGhD,oBAACA;IAAK,WAAU;IAAW,MAAK;IAAO,SAAQ;KAAW;KAFtD,OAGQ;GAEG,EAEjB,cAAc,KACd,oBAAC,OAAO;EACP,SAAS;GAAE,OAAO;GAAG,SAAS;GAAG;EACjC,WAAU;EACV,MAAM;GAAE,OAAO;GAAG,SAAS;GAAG;EAC9B,SAAS;GAAE,OAAO;GAAG,SAAS;GAAG;GAChC,IAED;;;;;;AAYL,MAAaC,kBAAiD,EAC7D,gBAEA,oBAACC;CAAkB;YAChB,EAAE,QAAQ,aAAa,eACxB,oBAAC,OAAO;EACP,WAAW,GACV,8MACA,UACA;EACD,aAAW;EACX,YAAY;GACX,MAAM;GACN,WAAW;GACX,SAAS;GACT;EACD,MAAK;EACL,UAAU,EAAE,OAAO,KAAM;YAEzB,oBAAC;GACQ;GACE;GACG;IACZ;GACa;EAEE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typing-indicator.d.ts","names":[],"sources":["../../../src/support/components/typing-indicator.tsx"],"sourcesContent":[],"mappings":";;;;KAKY,qBAAA;KAEA,iBAAA;EAFA,EAAA,EAAA,MAAA;EAEA,IAAA,EAEL,qBAFsB;AAK7B,CAAA;AAAwD,KAA5C,oBAAA,GAAuB,OAAA,CAAM,cAAe,CAAA,cAAA,CAAA,GAAA;EAArB,YAAM,EAC1B,iBAD0B,EAAA;EAC1B,iBAAA,CAAA,EACM,gBADN,EAAA;EACM,oBAAA,CAAA,EACG,mBADH,EAAA;EACG,WAAA,CAAA,EAAA,OAAA;CAAmB;AAI9B,cAAA,YAAgB,EAAA,CAAA;EAAA;CAIzB,EAAM;EAuBG,SAAA,CAAA,EAAA,
|
|
1
|
+
{"version":3,"file":"typing-indicator.d.ts","names":[],"sources":["../../../src/support/components/typing-indicator.tsx"],"sourcesContent":[],"mappings":";;;;KAKY,qBAAA;KAEA,iBAAA;EAFA,EAAA,EAAA,MAAA;EAEA,IAAA,EAEL,qBAFsB;AAK7B,CAAA;AAAwD,KAA5C,oBAAA,GAAuB,OAAA,CAAM,cAAe,CAAA,cAAA,CAAA,GAAA;EAArB,YAAM,EAC1B,iBAD0B,EAAA;EAC1B,iBAAA,CAAA,EACM,gBADN,EAAA;EACM,oBAAA,CAAA,EACG,mBADH,EAAA;EACG,WAAA,CAAA,EAAA,OAAA;CAAmB;AAI9B,cAAA,YAAgB,EAAA,CAAA;EAAA;CAIzB,EAAM;EAuBG,SAAA,CAAA,EAAA,MAwDZ;CAxD2B,EAAA,GAvBxB,OAAA,CAAM,YAuBkB;AAAA,cAAf,eAAe,EAAA,OAAA,CAAA,yBAAA,CAAA,OAAA,CAAA,cAAA,CAAA,cAAA,CAAA,GAAA;EAjCb,YAAA,EAAA,iBAAA,EAAA;EACM,iBAAA,CAAA,EAAA,gBAAA,EAAA;EACG,oBAAA,CAAA,EAAA,mBAAA,EAAA"}
|
|
@@ -24,6 +24,7 @@ const TypingIndicator = React$1.forwardRef(({ participants, availableAIAgents =
|
|
|
24
24
|
...props,
|
|
25
25
|
children: [withAvatars && /* @__PURE__ */ jsx(AvatarStack, {
|
|
26
26
|
aiAgents: typingAIAgents,
|
|
27
|
+
hideDefaultAIAgent: typingAIAgents.length === 0,
|
|
27
28
|
humanAgents: typingHumanAgents,
|
|
28
29
|
size: 24,
|
|
29
30
|
spacing: 16
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typing-indicator.js","names":["React"],"sources":["../../../src/support/components/typing-indicator.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport * as React from \"react\";\nimport { cn } from \"../utils\";\nimport { AvatarStack } from \"./avatar-stack\";\n\nexport type TypingParticipantType = \"visitor\" | \"team_member\" | \"ai\";\n\nexport type TypingParticipant = {\n\tid: string;\n\ttype: TypingParticipantType;\n};\n\nexport type TypingIndicatorProps = React.HTMLAttributes<HTMLDivElement> & {\n\tparticipants: TypingParticipant[];\n\tavailableAIAgents?: AvailableAIAgent[];\n\tavailableHumanAgents?: AvailableHumanAgent[];\n\twithAvatars?: boolean;\n};\n\nexport const BouncingDots = ({\n\tclassName,\n}: {\n\tclassName?: string;\n}): React.ReactElement => (\n\t<div className=\"flex gap-1\">\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-1 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-2 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-3 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t</div>\n);\n\nexport const TypingIndicator = React.forwardRef<\n\tHTMLDivElement,\n\tTypingIndicatorProps\n>(\n\t(\n\t\t{\n\t\t\tparticipants,\n\t\t\tavailableAIAgents = [],\n\t\t\tavailableHumanAgents = [],\n\t\t\twithAvatars = true,\n\t\t\tclassName,\n\t\t\t...props\n\t\t},\n\t\tref\n\t) => {\n\t\tif (!participants || participants.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Separate AI and human participants\n\t\tconst humanParticipantIds = participants\n\t\t\t.filter((p) => p.type === \"team_member\")\n\t\t\t.map((p) => p.id);\n\n\t\tconst aiParticipantIds = participants\n\t\t\t.filter((p) => p.type === \"ai\")\n\t\t\t.map((p) => p.id);\n\n\t\t// Get matching agents\n\t\tconst typingHumanAgents = availableHumanAgents.filter((agent) =>\n\t\t\thumanParticipantIds.includes(agent.id)\n\t\t);\n\n\t\tconst typingAIAgents = availableAIAgents.filter((agent) =>\n\t\t\taiParticipantIds.includes(agent.id)\n\t\t);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\"flex items-center gap-6\", className)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{withAvatars && (\n\t\t\t\t\t<AvatarStack\n\t\t\t\t\t\taiAgents={typingAIAgents}\n\t\t\t\t\t\thumanAgents={typingHumanAgents}\n\t\t\t\t\t\tsize={24}\n\t\t\t\t\t\tspacing={16}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<BouncingDots />\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nTypingIndicator.displayName = \"TypingIndicator\";\n"],"mappings":";;;;;;AAmBA,MAAa,gBAAgB,EAC5B,gBAIA,qBAAC;CAAI,WAAU;;EACd,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;EACF,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;EACF,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;;EACG;AAGP,MAAa,kBAAkBA,QAAM,YAKnC,EACC,cACA,oBAAoB,EAAE,EACtB,uBAAuB,EAAE,EACzB,cAAc,MACd,UACA,GAAG,SAEJ,QACI;AACJ,KAAI,CAAC,gBAAgB,aAAa,WAAW,EAC5C,QAAO;CAIR,MAAM,sBAAsB,aAC1B,QAAQ,MAAM,EAAE,SAAS,cAAc,CACvC,KAAK,MAAM,EAAE,GAAG;CAElB,MAAM,mBAAmB,aACvB,QAAQ,MAAM,EAAE,SAAS,KAAK,CAC9B,KAAK,MAAM,EAAE,GAAG;CAGlB,MAAM,oBAAoB,qBAAqB,QAAQ,UACtD,oBAAoB,SAAS,MAAM,GAAG,CACtC;CAED,MAAM,iBAAiB,kBAAkB,QAAQ,UAChD,iBAAiB,SAAS,MAAM,GAAG,CACnC;AAED,QACC,qBAAC;EACA,WAAW,GAAG,2BAA2B,UAAU;EAC9C;EACL,GAAI;aAEH,eACA,oBAAC;GACA,UAAU;GACV,aAAa;GACb,MAAM;GACN,SAAS;IACR,EAEH,oBAAC,iBAAe;GACX;EAGR;AAED,gBAAgB,cAAc"}
|
|
1
|
+
{"version":3,"file":"typing-indicator.js","names":["React"],"sources":["../../../src/support/components/typing-indicator.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport * as React from \"react\";\nimport { cn } from \"../utils\";\nimport { AvatarStack } from \"./avatar-stack\";\n\nexport type TypingParticipantType = \"visitor\" | \"team_member\" | \"ai\";\n\nexport type TypingParticipant = {\n\tid: string;\n\ttype: TypingParticipantType;\n};\n\nexport type TypingIndicatorProps = React.HTMLAttributes<HTMLDivElement> & {\n\tparticipants: TypingParticipant[];\n\tavailableAIAgents?: AvailableAIAgent[];\n\tavailableHumanAgents?: AvailableHumanAgent[];\n\twithAvatars?: boolean;\n};\n\nexport const BouncingDots = ({\n\tclassName,\n}: {\n\tclassName?: string;\n}): React.ReactElement => (\n\t<div className=\"flex gap-1\">\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-1 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-2 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-3 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t</div>\n);\n\nexport const TypingIndicator = React.forwardRef<\n\tHTMLDivElement,\n\tTypingIndicatorProps\n>(\n\t(\n\t\t{\n\t\t\tparticipants,\n\t\t\tavailableAIAgents = [],\n\t\t\tavailableHumanAgents = [],\n\t\t\twithAvatars = true,\n\t\t\tclassName,\n\t\t\t...props\n\t\t},\n\t\tref\n\t) => {\n\t\tif (!participants || participants.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Separate AI and human participants\n\t\tconst humanParticipantIds = participants\n\t\t\t.filter((p) => p.type === \"team_member\")\n\t\t\t.map((p) => p.id);\n\n\t\tconst aiParticipantIds = participants\n\t\t\t.filter((p) => p.type === \"ai\")\n\t\t\t.map((p) => p.id);\n\n\t\t// Get matching agents\n\t\tconst typingHumanAgents = availableHumanAgents.filter((agent) =>\n\t\t\thumanParticipantIds.includes(agent.id)\n\t\t);\n\n\t\tconst typingAIAgents = availableAIAgents.filter((agent) =>\n\t\t\taiParticipantIds.includes(agent.id)\n\t\t);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\"flex items-center gap-6\", className)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{withAvatars && (\n\t\t\t\t\t<AvatarStack\n\t\t\t\t\t\taiAgents={typingAIAgents}\n\t\t\t\t\t\thideDefaultAIAgent={typingAIAgents.length === 0}\n\t\t\t\t\t\thumanAgents={typingHumanAgents}\n\t\t\t\t\t\tsize={24}\n\t\t\t\t\t\tspacing={16}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<BouncingDots />\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nTypingIndicator.displayName = \"TypingIndicator\";\n"],"mappings":";;;;;;AAmBA,MAAa,gBAAgB,EAC5B,gBAIA,qBAAC;CAAI,WAAU;;EACd,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;EACF,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;EACF,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;;EACG;AAGP,MAAa,kBAAkBA,QAAM,YAKnC,EACC,cACA,oBAAoB,EAAE,EACtB,uBAAuB,EAAE,EACzB,cAAc,MACd,UACA,GAAG,SAEJ,QACI;AACJ,KAAI,CAAC,gBAAgB,aAAa,WAAW,EAC5C,QAAO;CAIR,MAAM,sBAAsB,aAC1B,QAAQ,MAAM,EAAE,SAAS,cAAc,CACvC,KAAK,MAAM,EAAE,GAAG;CAElB,MAAM,mBAAmB,aACvB,QAAQ,MAAM,EAAE,SAAS,KAAK,CAC9B,KAAK,MAAM,EAAE,GAAG;CAGlB,MAAM,oBAAoB,qBAAqB,QAAQ,UACtD,oBAAoB,SAAS,MAAM,GAAG,CACtC;CAED,MAAM,iBAAiB,kBAAkB,QAAQ,UAChD,iBAAiB,SAAS,MAAM,GAAG,CACnC;AAED,QACC,qBAAC;EACA,WAAW,GAAG,2BAA2B,UAAU;EAC9C;EACL,GAAI;aAEH,eACA,oBAAC;GACA,UAAU;GACV,oBAAoB,eAAe,WAAW;GAC9C,aAAa;GACb,MAAM;GACN,SAAS;IACR,EAEH,oBAAC,iBAAe;GACX;EAGR;AAED,gBAAgB,cAAc"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/support/context/controlled-state.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Controlled state context for the Support widget.
|
|
7
|
+
* Allows external control of widget open/close state.
|
|
8
|
+
*/
|
|
9
|
+
type ControlledStateContextValue = {
|
|
10
|
+
/**
|
|
11
|
+
* Controlled open state (undefined = uncontrolled)
|
|
12
|
+
*/
|
|
13
|
+
open: boolean | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Callback when open state should change
|
|
16
|
+
*/
|
|
17
|
+
onOpenChange: ((open: boolean) => void) | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Whether the component is in controlled mode
|
|
20
|
+
*/
|
|
21
|
+
isControlled: boolean;
|
|
22
|
+
};
|
|
23
|
+
type ControlledStateProviderProps = {
|
|
24
|
+
/**
|
|
25
|
+
* Controlled open state
|
|
26
|
+
*/
|
|
27
|
+
open?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Callback when open state changes
|
|
30
|
+
*/
|
|
31
|
+
onOpenChange?: (open: boolean) => void;
|
|
32
|
+
children: React$1.ReactNode;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Provider for controlled widget state.
|
|
36
|
+
* Wraps the Support component to enable controlled mode.
|
|
37
|
+
*/
|
|
38
|
+
declare const ControlledStateProvider: React$1.FC<ControlledStateProviderProps>;
|
|
39
|
+
/**
|
|
40
|
+
* Access controlled state context.
|
|
41
|
+
* Returns null if not inside a ControlledStateProvider.
|
|
42
|
+
*/
|
|
43
|
+
declare function useControlledState(): ControlledStateContextValue | null;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { ControlledStateContextValue, ControlledStateProvider, ControlledStateProviderProps, useControlledState };
|
|
46
|
+
//# sourceMappingURL=controlled-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controlled-state.d.ts","names":[],"sources":["../../../src/support/context/controlled-state.tsx"],"sourcesContent":[],"mappings":";;;;;;AAQA;AAkBA;AAgBa,KAlCD,2BAAA,GAmDX;EAMe;;;;;;;;;;;;;KAvCJ,4BAAA;;;;;;;;;YASD,OAAA,CAAM;;;;;;cAOJ,yBAAyB,OAAA,CAAM,GAC3C;;;;;iBAsBe,kBAAA,CAAA,GAAsB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import * as React$1 from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/support/context/controlled-state.tsx
|
|
8
|
+
const ControlledStateContext = React$1.createContext(null);
|
|
9
|
+
/**
|
|
10
|
+
* Provider for controlled widget state.
|
|
11
|
+
* Wraps the Support component to enable controlled mode.
|
|
12
|
+
*/
|
|
13
|
+
const ControlledStateProvider = ({ open, onOpenChange, children }) => {
|
|
14
|
+
const value = React$1.useMemo(() => ({
|
|
15
|
+
open,
|
|
16
|
+
onOpenChange,
|
|
17
|
+
isControlled: open !== void 0
|
|
18
|
+
}), [open, onOpenChange]);
|
|
19
|
+
return /* @__PURE__ */ jsx(ControlledStateContext.Provider, {
|
|
20
|
+
value,
|
|
21
|
+
children
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Access controlled state context.
|
|
26
|
+
* Returns null if not inside a ControlledStateProvider.
|
|
27
|
+
*/
|
|
28
|
+
function useControlledState() {
|
|
29
|
+
return React$1.useContext(ControlledStateContext);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { ControlledStateProvider, useControlledState };
|
|
34
|
+
//# sourceMappingURL=controlled-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controlled-state.js","names":["React","ControlledStateProvider: React.FC<\n\tControlledStateProviderProps\n>"],"sources":["../../../src/support/context/controlled-state.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\n/**\n * Controlled state context for the Support widget.\n * Allows external control of widget open/close state.\n */\nexport type ControlledStateContextValue = {\n\t/**\n\t * Controlled open state (undefined = uncontrolled)\n\t */\n\topen: boolean | undefined;\n\t/**\n\t * Callback when open state should change\n\t */\n\tonOpenChange: ((open: boolean) => void) | undefined;\n\t/**\n\t * Whether the component is in controlled mode\n\t */\n\tisControlled: boolean;\n};\n\nconst ControlledStateContext =\n\tReact.createContext<ControlledStateContextValue | null>(null);\n\nexport type ControlledStateProviderProps = {\n\t/**\n\t * Controlled open state\n\t */\n\topen?: boolean;\n\t/**\n\t * Callback when open state changes\n\t */\n\tonOpenChange?: (open: boolean) => void;\n\tchildren: React.ReactNode;\n};\n\n/**\n * Provider for controlled widget state.\n * Wraps the Support component to enable controlled mode.\n */\nexport const ControlledStateProvider: React.FC<\n\tControlledStateProviderProps\n> = ({ open, onOpenChange, children }) => {\n\tconst value = React.useMemo<ControlledStateContextValue>(\n\t\t() => ({\n\t\t\topen,\n\t\t\tonOpenChange,\n\t\t\tisControlled: open !== undefined,\n\t\t}),\n\t\t[open, onOpenChange]\n\t);\n\n\treturn (\n\t\t<ControlledStateContext.Provider value={value}>\n\t\t\t{children}\n\t\t</ControlledStateContext.Provider>\n\t);\n};\n\n/**\n * Access controlled state context.\n * Returns null if not inside a ControlledStateProvider.\n */\nexport function useControlledState(): ControlledStateContextValue | null {\n\treturn React.useContext(ControlledStateContext);\n}\n"],"mappings":";;;;;;;AAuBA,MAAM,yBACLA,QAAM,cAAkD,KAAK;;;;;AAkB9D,MAAaC,2BAER,EAAE,MAAM,cAAc,eAAe;CACzC,MAAM,QAAQD,QAAM,eACZ;EACN;EACA;EACA,cAAc,SAAS;EACvB,GACD,CAAC,MAAM,aAAa,CACpB;AAED,QACC,oBAAC,uBAAuB;EAAgB;EACtC;GACgC;;;;;;AAQpC,SAAgB,qBAAyD;AACxE,QAAOA,QAAM,WAAW,uBAAuB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { TimelineItem } from "../../timeline-item.js";
|
|
2
|
+
import * as React$1 from "react";
|
|
3
|
+
import { Conversation } from "@cossistant/types";
|
|
4
|
+
|
|
5
|
+
//#region src/support/context/events.d.ts
|
|
6
|
+
type SupportEventType = "conversationStart" | "conversationEnd" | "messageSent" | "messageReceived" | "error";
|
|
7
|
+
type ConversationStartEvent = {
|
|
8
|
+
type: "conversationStart";
|
|
9
|
+
conversationId: string;
|
|
10
|
+
conversation?: Conversation;
|
|
11
|
+
};
|
|
12
|
+
type ConversationEndEvent = {
|
|
13
|
+
type: "conversationEnd";
|
|
14
|
+
conversationId: string;
|
|
15
|
+
conversation?: Conversation;
|
|
16
|
+
};
|
|
17
|
+
type MessageSentEvent = {
|
|
18
|
+
type: "messageSent";
|
|
19
|
+
conversationId: string;
|
|
20
|
+
message: TimelineItem;
|
|
21
|
+
};
|
|
22
|
+
type MessageReceivedEvent = {
|
|
23
|
+
type: "messageReceived";
|
|
24
|
+
conversationId: string;
|
|
25
|
+
message: TimelineItem;
|
|
26
|
+
};
|
|
27
|
+
type ErrorEvent = {
|
|
28
|
+
type: "error";
|
|
29
|
+
error: Error;
|
|
30
|
+
context?: string;
|
|
31
|
+
};
|
|
32
|
+
type SupportEvent = ConversationStartEvent | ConversationEndEvent | MessageSentEvent | MessageReceivedEvent | ErrorEvent;
|
|
33
|
+
type SupportEventCallbacks = {
|
|
34
|
+
/**
|
|
35
|
+
* Called when a new conversation is started.
|
|
36
|
+
*/
|
|
37
|
+
onConversationStart?: (event: ConversationStartEvent) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Called when a conversation ends (resolved, closed, etc.).
|
|
40
|
+
*/
|
|
41
|
+
onConversationEnd?: (event: ConversationEndEvent) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Called when the visitor sends a message.
|
|
44
|
+
*/
|
|
45
|
+
onMessageSent?: (event: MessageSentEvent) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Called when a message is received from an agent (human or AI).
|
|
48
|
+
*/
|
|
49
|
+
onMessageReceived?: (event: MessageReceivedEvent) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Called when an error occurs.
|
|
52
|
+
*/
|
|
53
|
+
onError?: (event: ErrorEvent) => void;
|
|
54
|
+
};
|
|
55
|
+
type SupportEventsContextValue = {
|
|
56
|
+
/**
|
|
57
|
+
* Emit an event to all registered callbacks.
|
|
58
|
+
*/
|
|
59
|
+
emit: <T extends SupportEvent>(event: T) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Subscribe to a specific event type.
|
|
62
|
+
* Returns an unsubscribe function.
|
|
63
|
+
*/
|
|
64
|
+
subscribe: <T extends SupportEventType>(type: T, callback: (event: Extract<SupportEvent, {
|
|
65
|
+
type: T;
|
|
66
|
+
}>) => void) => () => void;
|
|
67
|
+
};
|
|
68
|
+
type SupportEventsProviderProps = SupportEventCallbacks & {
|
|
69
|
+
children: React$1.ReactNode;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Provider for support widget events.
|
|
73
|
+
* Allows listening to lifecycle events like message sent/received,
|
|
74
|
+
* conversation start/end, and errors.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* <Support
|
|
78
|
+
* onMessageSent={({ message }) => console.log("Sent:", message)}
|
|
79
|
+
* onMessageReceived={({ message }) => console.log("Received:", message)}
|
|
80
|
+
* onConversationStart={({ conversationId }) => console.log("Started:", conversationId)}
|
|
81
|
+
* onError={({ error }) => console.error("Error:", error)}
|
|
82
|
+
* />
|
|
83
|
+
*/
|
|
84
|
+
declare const SupportEventsProvider: React$1.FC<SupportEventsProviderProps>;
|
|
85
|
+
/**
|
|
86
|
+
* Access the events context.
|
|
87
|
+
* Returns null if not inside a SupportEventsProvider.
|
|
88
|
+
*/
|
|
89
|
+
declare function useSupportEvents(): SupportEventsContextValue | null;
|
|
90
|
+
/**
|
|
91
|
+
* Hook to emit events from within the widget.
|
|
92
|
+
* Safe to use outside of provider (will no-op).
|
|
93
|
+
*/
|
|
94
|
+
declare function useSupportEventEmitter(): {
|
|
95
|
+
emitConversationStart: (conversationId: string, conversation?: Conversation) => void;
|
|
96
|
+
emitConversationEnd: (conversationId: string, conversation?: Conversation) => void;
|
|
97
|
+
emitMessageSent: (conversationId: string, message: TimelineItem) => void;
|
|
98
|
+
emitMessageReceived: (conversationId: string, message: TimelineItem) => void;
|
|
99
|
+
emitError: (error: Error, context?: string) => void;
|
|
100
|
+
};
|
|
101
|
+
//#endregion
|
|
102
|
+
export { ConversationEndEvent, ConversationStartEvent, ErrorEvent, MessageReceivedEvent, MessageSentEvent, SupportEvent, SupportEventCallbacks, SupportEventType, SupportEventsContextValue, SupportEventsProvider, SupportEventsProviderProps, useSupportEventEmitter, useSupportEvents };
|
|
103
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","names":[],"sources":["../../../src/support/context/events.tsx"],"sourcesContent":[],"mappings":";;;;;KAUY,gBAAA;KAOA,sBAAA;EAPA,IAAA,EAAA,mBAAgB;EAOhB,cAAA,EAAA,MAAA;EAMA,YAAA,CAAA,EAHI,YAGgB;AAMhC,CAAA;AAMY,KAZA,oBAAA,GAYoB;EAMpB,IAAA,EAAA,iBAAU;EAMV,cAAA,EAAY,MAAA;EACrB,YAAA,CAAA,EAtBa,YAsBb;CACA;AACA,KArBS,gBAAA,GAqBT;EACA,IAAA,EAAA,aAAA;EACA,cAAA,EAAA,MAAA;EAAU,OAAA,EApBH,YAoBG;AAMb,CAAA;AAI+B,KA3BnB,oBAAA,GA2BmB;EAIF,IAAA,EAAA,iBAAA;EAIJ,cAAA,EAAA,MAAA;EAII,OAAA,EApCnB,YAoCmB;CAIV;AAAU,KArCjB,UAAA,GAqCiB;EAOjB,IAAA,EAAA,OAAA;EAIM,KAAA,EA9CV,KA8CU;EAAqB,OAAA,CAAA,EAAA,MAAA;CAKhB;AACf,KAhDI,YAAA,GACT,sBA+CK,GA9CL,oBA8CK,GA7CL,gBA6CK,GA5CL,oBA4CK,GA3CL,UA2CK;AACoB,KAtChB,qBAAA,GAsCgB;EAAsB;;;EAOtC,mBAAA,CAAA,EAAA,CAAA,KAAA,EAzCmB,sBAyCU,EAAA,GAAA,IAAA;EAiB5B;AA0Gb;AAQA;EAOmB,iBAAA,CAAA,EAAA,CAAA,KAAA,EA/KU,oBA+KV,EAAA,GAAA,IAAA;EAUA;;;EAsBG,aAAA,CAAA,EAAA,CAAA,KAAA,EA3MG,gBA2MH,EAAA,GAAA,IAAA;EAAK;;;8BAvME;;;;oBAIV;;KAOP,yBAAA;;;;mBAIM,qBAAqB;;;;;wBAKhB,wBACf,qBACY,QAAQ;UAAsB;;;KAOtC,0BAAA,GAA6B;YAC9B,OAAA,CAAM;;;;;;;;;;;;;;;cAgBJ,uBAAuB,OAAA,CAAM,GAAG;;;;;iBA0G7B,gBAAA,CAAA,GAAoB;;;;;iBAQpB,sBAAA,CAAA;iEAOG;+DAUA;qDAQmC;yDAOI;qBAOpC"}
|