@admin-layout/tailwind-chat-pro 12.2.4-alpha.76
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/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/lib/components/index.d.ts +2 -0
- package/lib/components/index.d.ts.map +1 -0
- package/lib/components/messages-container-ui/DefaultInputToolBar.d.ts +21 -0
- package/lib/components/messages-container-ui/DefaultInputToolBar.d.ts.map +1 -0
- package/lib/components/messages-container-ui/DefaultInputToolBar.js +46 -0
- package/lib/components/messages-container-ui/DefaultInputToolBar.js.map +1 -0
- package/lib/components/messages-container-ui/DefaultMessageGroup.d.ts +16 -0
- package/lib/components/messages-container-ui/DefaultMessageGroup.d.ts.map +1 -0
- package/lib/components/messages-container-ui/DefaultMessageGroup.js +64 -0
- package/lib/components/messages-container-ui/DefaultMessageGroup.js.map +1 -0
- package/lib/components/messages-container-ui/MessagesContainerUI.d.ts +98 -0
- package/lib/components/messages-container-ui/MessagesContainerUI.d.ts.map +1 -0
- package/lib/components/messages-container-ui/MessagesContainerUI.js +88 -0
- package/lib/components/messages-container-ui/MessagesContainerUI.js.map +1 -0
- package/lib/components/messages-container-ui/PlanModeView.d.ts +107 -0
- package/lib/components/messages-container-ui/PlanModeView.d.ts.map +1 -0
- package/lib/components/messages-container-ui/PlanModeView.js +294 -0
- package/lib/components/messages-container-ui/PlanModeView.js.map +1 -0
- package/lib/components/messages-container-ui/index.d.ts +9 -0
- package/lib/components/messages-container-ui/index.d.ts.map +1 -0
- package/lib/components/messages-container-ui/types.d.ts +63 -0
- package/lib/components/messages-container-ui/types.d.ts.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -0
- package/lib/routes.json +1 -0
- package/package.json +42 -0
- package/rollup.config.mjs +34 -0
- package/src/components/index.ts +1 -0
- package/src/components/messages-container-ui/DefaultInputToolBar.tsx +63 -0
- package/src/components/messages-container-ui/DefaultMessageGroup.tsx +75 -0
- package/src/components/messages-container-ui/MessagesContainerUI.tsx +178 -0
- package/src/components/messages-container-ui/PlanModeView.tsx +457 -0
- package/src/components/messages-container-ui/index.ts +8 -0
- package/src/components/messages-container-ui/types.ts +68 -0
- package/src/index.ts +1 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import {jsxs,jsx,Fragment}from'react/jsx-runtime';import {useState,useRef,useCallback,useMemo,useLayoutEffect,useEffect}from'react';import clsx from'clsx';import {AiAgentMessageRole,PostTypeEnum}from'common';import {DefaultMessageGroup}from'./DefaultMessageGroup.js';import {DefaultInputToolBar}from'./DefaultInputToolBar.js';const ASSISTANT_BUBBLE_BG = 'bg-white';
|
|
2
|
+
const BORDER_COLOR = 'border-gray-200';
|
|
3
|
+
const HIDE_SCROLLBAR_CSS = `
|
|
4
|
+
/* Hide scrollbar while keeping scrollability */
|
|
5
|
+
.ym-hide-scrollbar {
|
|
6
|
+
-ms-overflow-style: none; /* IE/Edge */
|
|
7
|
+
scrollbar-width: none; /* Firefox */
|
|
8
|
+
}
|
|
9
|
+
.ym-hide-scrollbar::-webkit-scrollbar {
|
|
10
|
+
display: none; /* Chrome/Safari */
|
|
11
|
+
width: 0;
|
|
12
|
+
height: 0;
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
15
|
+
const DEFAULT_ASSISTANT_AUTHOR = {
|
|
16
|
+
id: 'ai-assistant',
|
|
17
|
+
givenName: 'AI',
|
|
18
|
+
familyName: 'Assistant',
|
|
19
|
+
fullName: 'AI Assistant',
|
|
20
|
+
username: 'ai-assistant',
|
|
21
|
+
email: 'ai@assistant.com',
|
|
22
|
+
picture: null,
|
|
23
|
+
alias: [],
|
|
24
|
+
tokens: []
|
|
25
|
+
};
|
|
26
|
+
/** Default mapping of a PlanMessage to the post-like shape expected by message-group renderers. */
|
|
27
|
+
function defaultPlanMessageToPost(msg, currentUser) {
|
|
28
|
+
const isUser = msg.role === 'user';
|
|
29
|
+
const author = msg.author ?? (isUser ? {
|
|
30
|
+
id: currentUser.id,
|
|
31
|
+
givenName: currentUser.givenName ?? currentUser.name ?? 'User',
|
|
32
|
+
familyName: currentUser.familyName ?? '',
|
|
33
|
+
fullName: currentUser.fullName ?? currentUser.name ?? 'User',
|
|
34
|
+
username: currentUser.username ?? currentUser.id,
|
|
35
|
+
email: currentUser.email ?? '',
|
|
36
|
+
picture: currentUser.picture ?? currentUser.avatar ?? null,
|
|
37
|
+
alias: currentUser.alias ?? [],
|
|
38
|
+
tokens: currentUser.tokens ?? []
|
|
39
|
+
} : DEFAULT_ASSISTANT_AUTHOR);
|
|
40
|
+
return {
|
|
41
|
+
id: msg.id,
|
|
42
|
+
message: msg.content,
|
|
43
|
+
author,
|
|
44
|
+
createdAt: msg.createdAt ?? new Date().toISOString(),
|
|
45
|
+
type: msg.type ?? PostTypeEnum.Aiassistant,
|
|
46
|
+
isDelivered: false,
|
|
47
|
+
isRead: false,
|
|
48
|
+
parentId: null,
|
|
49
|
+
fromServer: null,
|
|
50
|
+
updatedAt: msg.createdAt ?? new Date().toISOString(),
|
|
51
|
+
propsConfiguration: {
|
|
52
|
+
...(msg.propsConfiguration ?? {
|
|
53
|
+
contents: {}
|
|
54
|
+
}),
|
|
55
|
+
contents: {
|
|
56
|
+
...(msg.propsConfiguration?.contents ?? {}),
|
|
57
|
+
role: msg.propsConfiguration?.contents?.role ?? (isUser ? AiAgentMessageRole.User : AiAgentMessageRole.Assistant),
|
|
58
|
+
// Plan/build mode: consumers (e.g. ModernMessageBubble) read propsConfiguration.contents.mode
|
|
59
|
+
...(msg.props?.mode != null ? {
|
|
60
|
+
mode: msg.props.mode
|
|
61
|
+
} : {})
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
props: msg.props ?? {},
|
|
65
|
+
files: msg.files ?? [],
|
|
66
|
+
replies: null,
|
|
67
|
+
channel: null,
|
|
68
|
+
isPinned: false
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function PlanModeView({
|
|
72
|
+
messages,
|
|
73
|
+
streamingContent,
|
|
74
|
+
currentUser,
|
|
75
|
+
onSend,
|
|
76
|
+
disabled = false,
|
|
77
|
+
isLoading = false,
|
|
78
|
+
onStop,
|
|
79
|
+
showDate = false,
|
|
80
|
+
showAvatar = false,
|
|
81
|
+
showMessageBubbleBorder = false,
|
|
82
|
+
useInternalScroll = false,
|
|
83
|
+
scrollContainerRef,
|
|
84
|
+
scrollContainerClassName,
|
|
85
|
+
hideScrollbar = false,
|
|
86
|
+
contentClassName,
|
|
87
|
+
postContainerClassName,
|
|
88
|
+
className,
|
|
89
|
+
hideInputToolbar = false,
|
|
90
|
+
inputPlacement = 'bottom',
|
|
91
|
+
renderInputToolbar,
|
|
92
|
+
inputPlaceholder,
|
|
93
|
+
onOpen = () => {},
|
|
94
|
+
onMessageClick = () => {},
|
|
95
|
+
isDesktopView = false,
|
|
96
|
+
isSmallScreen = false,
|
|
97
|
+
sandboxErrors = [],
|
|
98
|
+
currentFiles = {},
|
|
99
|
+
onFixError,
|
|
100
|
+
error = null,
|
|
101
|
+
onRetry,
|
|
102
|
+
renderEmptyState,
|
|
103
|
+
scrollToBottomDeps,
|
|
104
|
+
showCopyDownloadOnCodeBlock = true,
|
|
105
|
+
MessageGroupComponent = DefaultMessageGroup,
|
|
106
|
+
renderStreamingContent,
|
|
107
|
+
mapMessageToPost = defaultPlanMessageToPost
|
|
108
|
+
}) {
|
|
109
|
+
const [inputValue, setInputValue] = useState('');
|
|
110
|
+
const internalListRef = useRef(null);
|
|
111
|
+
const contentRef = useRef(null);
|
|
112
|
+
const shouldAutoScrollRef = useRef(true);
|
|
113
|
+
const setScrollContainerRef = useCallback(node => {
|
|
114
|
+
internalListRef.current = node;
|
|
115
|
+
if (!scrollContainerRef) return;
|
|
116
|
+
if (typeof scrollContainerRef === 'function') {
|
|
117
|
+
scrollContainerRef(node);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// RefObject / MutableRefObject
|
|
121
|
+
scrollContainerRef.current = node;
|
|
122
|
+
}, [scrollContainerRef]);
|
|
123
|
+
const scrollToBottom = useCallback(() => {
|
|
124
|
+
const el = internalListRef.current;
|
|
125
|
+
if (el && shouldAutoScrollRef.current) {
|
|
126
|
+
el.scrollTop = el.scrollHeight;
|
|
127
|
+
}
|
|
128
|
+
}, []);
|
|
129
|
+
const handleSendFromInput = useCallback(() => {
|
|
130
|
+
const t = inputValue.trim();
|
|
131
|
+
if (!t) return;
|
|
132
|
+
onSend(t);
|
|
133
|
+
setInputValue('');
|
|
134
|
+
}, [inputValue, onSend]);
|
|
135
|
+
const inputToolbarProps = {
|
|
136
|
+
value: inputValue,
|
|
137
|
+
onChange: setInputValue,
|
|
138
|
+
onSend: handleSendFromInput,
|
|
139
|
+
disabled: disabled || isLoading
|
|
140
|
+
};
|
|
141
|
+
// Default the input composer to @admin-layout/tailwind-ui's InputToolBar (the shared
|
|
142
|
+
// "ai-tool-box"); consumers can override with `renderInputToolbar` for a richer composer.
|
|
143
|
+
const renderToolbar = renderInputToolbar ?? (p => jsx(DefaultInputToolBar, {
|
|
144
|
+
...p,
|
|
145
|
+
isLoading: isLoading,
|
|
146
|
+
onStop: onStop,
|
|
147
|
+
placeholder: inputPlaceholder
|
|
148
|
+
}));
|
|
149
|
+
const currentUserForGroup = useMemo(() => ({
|
|
150
|
+
id: currentUser.id,
|
|
151
|
+
givenName: currentUser.givenName ?? currentUser.name ?? 'You',
|
|
152
|
+
familyName: currentUser.familyName ?? '',
|
|
153
|
+
fullName: currentUser.fullName ?? currentUser.name ?? 'You',
|
|
154
|
+
username: currentUser.username ?? currentUser.id,
|
|
155
|
+
email: currentUser.email ?? '',
|
|
156
|
+
picture: currentUser.picture ?? currentUser.avatar ?? null,
|
|
157
|
+
alias: currentUser.alias ?? [],
|
|
158
|
+
tokens: currentUser.tokens ?? []
|
|
159
|
+
}), [currentUser]);
|
|
160
|
+
const posts = useMemo(() => messages.map(m => mapMessageToPost(m, currentUser)), [messages, currentUser, mapMessageToPost]);
|
|
161
|
+
const isEmpty = posts.length === 0 && !streamingContent?.trim() && !isLoading;
|
|
162
|
+
const shouldInlineToolbar = inputPlacement === 'inlineWhenEmpty' && isEmpty;
|
|
163
|
+
const shouldRenderBottomToolbar = !hideInputToolbar && !shouldInlineToolbar;
|
|
164
|
+
// Auto-scroll to bottom while user stays near bottom.
|
|
165
|
+
useLayoutEffect(() => {
|
|
166
|
+
if (!useInternalScroll) return;
|
|
167
|
+
if (!shouldAutoScrollRef.current) return;
|
|
168
|
+
scrollToBottom();
|
|
169
|
+
const id = requestAnimationFrame(() => {
|
|
170
|
+
scrollToBottom();
|
|
171
|
+
requestAnimationFrame(scrollToBottom);
|
|
172
|
+
});
|
|
173
|
+
return () => cancelAnimationFrame(id);
|
|
174
|
+
}, [useInternalScroll, scrollToBottom, posts.length, streamingContent, isLoading]);
|
|
175
|
+
// When internal scroll is (re)enabled, force follow-to-bottom.
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
if (!useInternalScroll) return;
|
|
178
|
+
shouldAutoScrollRef.current = true;
|
|
179
|
+
scrollToBottom();
|
|
180
|
+
}, [useInternalScroll, scrollToBottom]);
|
|
181
|
+
// When inner content grows (stream chunks, markdown expand), scroll to bottom if user was near bottom.
|
|
182
|
+
// Observing the content wrapper ensures we react to content height changes; the scroll container size often does not change.
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
if (!useInternalScroll) return;
|
|
185
|
+
const el = contentRef.current;
|
|
186
|
+
if (!el) return;
|
|
187
|
+
if (typeof ResizeObserver === 'undefined') return;
|
|
188
|
+
const ro = new ResizeObserver(() => {
|
|
189
|
+
if (!shouldAutoScrollRef.current) return;
|
|
190
|
+
scrollToBottom();
|
|
191
|
+
});
|
|
192
|
+
ro.observe(el);
|
|
193
|
+
return () => ro.disconnect();
|
|
194
|
+
}, [useInternalScroll, scrollToBottom]);
|
|
195
|
+
// Parent-controlled scroll: when scrollToBottomDeps change (e.g. each stream chunk), force scroll to bottom.
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
if (!useInternalScroll || !scrollToBottomDeps?.length) return;
|
|
198
|
+
scrollToBottom();
|
|
199
|
+
const id = requestAnimationFrame(() => {
|
|
200
|
+
scrollToBottom();
|
|
201
|
+
});
|
|
202
|
+
return () => cancelAnimationFrame(id);
|
|
203
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- intentional: parent passes deps
|
|
204
|
+
}, scrollToBottomDeps ?? []);
|
|
205
|
+
const handleScroll = useCallback(() => {
|
|
206
|
+
const el = internalListRef.current;
|
|
207
|
+
if (!el) return;
|
|
208
|
+
const thresholdPx = 160;
|
|
209
|
+
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
210
|
+
shouldAutoScrollRef.current = distanceFromBottom <= thresholdPx;
|
|
211
|
+
}, []);
|
|
212
|
+
return jsxs("div", {
|
|
213
|
+
className: clsx('flex flex-col flex-1 min-h-0 overflow-hidden', className),
|
|
214
|
+
children: [useInternalScroll && hideScrollbar && jsx("style", {
|
|
215
|
+
children: HIDE_SCROLLBAR_CSS
|
|
216
|
+
}), jsx("div", {
|
|
217
|
+
ref: setScrollContainerRef,
|
|
218
|
+
onScroll: useInternalScroll ? handleScroll : undefined,
|
|
219
|
+
className: useInternalScroll ? clsx('flex-1 min-h-0 overflow-y-auto', hideScrollbar && 'ym-hide-scrollbar', scrollContainerClassName) : scrollContainerClassName ?? '',
|
|
220
|
+
children: jsxs("div", {
|
|
221
|
+
ref: contentRef,
|
|
222
|
+
className: clsx('w-full pb-4 pt-2 space-y-3 px-4', contentClassName ?? ''),
|
|
223
|
+
children: [error && jsxs("div", {
|
|
224
|
+
className: "rounded-lg border border-red-200 bg-red-50 px-4 py-3 flex items-center justify-between gap-2",
|
|
225
|
+
children: [jsx("span", {
|
|
226
|
+
className: "text-sm text-red-800",
|
|
227
|
+
children: error
|
|
228
|
+
}), onRetry && jsx("button", {
|
|
229
|
+
type: "button",
|
|
230
|
+
onClick: onRetry,
|
|
231
|
+
className: "shrink-0 px-3 py-1.5 text-sm font-medium text-red-700 hover:bg-red-100 rounded-md transition-colors",
|
|
232
|
+
children: "Retry"
|
|
233
|
+
})]
|
|
234
|
+
}), isEmpty && jsxs("div", {
|
|
235
|
+
className: "px-4 py-8 text-center",
|
|
236
|
+
children: [renderEmptyState ? renderEmptyState({
|
|
237
|
+
inputToolbarProps
|
|
238
|
+
}) : jsxs(Fragment, {
|
|
239
|
+
children: [jsx("div", {
|
|
240
|
+
className: "text-gray-500 text-lg font-medium mb-2",
|
|
241
|
+
children: "Describe your idea and I'll help you create it step by step"
|
|
242
|
+
}), jsx("div", {
|
|
243
|
+
className: "text-gray-400 text-sm",
|
|
244
|
+
children: "Start a new conversation by typing your message below"
|
|
245
|
+
})]
|
|
246
|
+
}), shouldInlineToolbar && jsx("div", {
|
|
247
|
+
className: "mt-6 text-left",
|
|
248
|
+
children: renderToolbar(inputToolbarProps)
|
|
249
|
+
})]
|
|
250
|
+
}), posts.map(post => jsx("div", {
|
|
251
|
+
className: clsx('mb-3', postContainerClassName),
|
|
252
|
+
children: jsx(MessageGroupComponent, {
|
|
253
|
+
messages: [post],
|
|
254
|
+
currentUser: currentUserForGroup,
|
|
255
|
+
onOpen: onOpen,
|
|
256
|
+
onMessageClick: onMessageClick,
|
|
257
|
+
isDesktopView: isDesktopView,
|
|
258
|
+
isSmallScreen: isSmallScreen,
|
|
259
|
+
showAuthorName: showAvatar,
|
|
260
|
+
showAvatar: showAvatar,
|
|
261
|
+
showTimestamp: showDate,
|
|
262
|
+
sandboxErrors: sandboxErrors,
|
|
263
|
+
currentFiles: currentFiles,
|
|
264
|
+
onFixError: onFixError,
|
|
265
|
+
showCopyDownloadOnCodeBlock: showCopyDownloadOnCodeBlock
|
|
266
|
+
})
|
|
267
|
+
}, post.id)), streamingContent?.trim() && jsx("div", {
|
|
268
|
+
className: "flex justify-start",
|
|
269
|
+
children: jsx("div", {
|
|
270
|
+
className: clsx('max-w-[85%] w-full rounded-2xl px-4 py-3 text-gray-900', ASSISTANT_BUBBLE_BG, showMessageBubbleBorder && `border ${BORDER_COLOR}`),
|
|
271
|
+
children: jsx("div", {
|
|
272
|
+
className: "min-w-0 text-[15px] leading-relaxed break-words whitespace-pre-wrap",
|
|
273
|
+
children: renderStreamingContent ? renderStreamingContent(streamingContent) : streamingContent
|
|
274
|
+
})
|
|
275
|
+
})
|
|
276
|
+
}), isLoading && jsx("div", {
|
|
277
|
+
className: "flex justify-start",
|
|
278
|
+
children: jsxs("div", {
|
|
279
|
+
className: "rounded-2xl px-4 py-3 bg-gray-100 border border-gray-200 flex items-center gap-2",
|
|
280
|
+
children: [jsx("div", {
|
|
281
|
+
className: "w-4 h-4 border-2 border-gray-300 border-t-gray-600 rounded-full animate-spin"
|
|
282
|
+
}), jsx("span", {
|
|
283
|
+
className: "text-sm text-gray-600",
|
|
284
|
+
children: "Thinking..."
|
|
285
|
+
})]
|
|
286
|
+
})
|
|
287
|
+
})]
|
|
288
|
+
})
|
|
289
|
+
}), shouldRenderBottomToolbar && jsx("div", {
|
|
290
|
+
className: "border-t border-gray-200 bg-white p-3",
|
|
291
|
+
children: renderToolbar(inputToolbarProps)
|
|
292
|
+
})]
|
|
293
|
+
});
|
|
294
|
+
}export{PlanModeView,defaultPlanMessageToPost};//# sourceMappingURL=PlanModeView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlanModeView.js","sources":["../../../src/components/messages-container-ui/PlanModeView.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { MessagesContainerUI } from './MessagesContainerUI';
|
|
2
|
+
export type { MessagesContainerUIProps } from './MessagesContainerUI';
|
|
3
|
+
export { PlanModeView, defaultPlanMessageToPost } from './PlanModeView';
|
|
4
|
+
export type { PlanModeViewProps, PlanModeViewInputToolbarProps } from './PlanModeView';
|
|
5
|
+
export { DefaultMessageGroup } from './DefaultMessageGroup';
|
|
6
|
+
export { DefaultInputToolBar } from './DefaultInputToolBar';
|
|
7
|
+
export type { DefaultInputToolBarProps } from './DefaultInputToolBar';
|
|
8
|
+
export type { PlanMessage, CurrentUser, MessageGroupRenderProps, MessageGroupComponentType } from './types';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/messages-container-ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AACxE,YAAY,EAAE,iBAAiB,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Messages container UI – types for plan mode (chat / search / research).
|
|
4
|
+
* Messages can be a simple PlanMessage or a full post-like shape passed through
|
|
5
|
+
* to the injected message-group renderer.
|
|
6
|
+
*/
|
|
7
|
+
export interface PlanMessage {
|
|
8
|
+
id: string;
|
|
9
|
+
role: 'user' | 'assistant' | 'system';
|
|
10
|
+
content: string;
|
|
11
|
+
createdAt?: Date | string;
|
|
12
|
+
/** Optional: pass through to the injected message-group renderer (propsConfiguration, props, files, etc.) */
|
|
13
|
+
propsConfiguration?: any;
|
|
14
|
+
props?: any;
|
|
15
|
+
files?: any;
|
|
16
|
+
author?: any;
|
|
17
|
+
type?: string;
|
|
18
|
+
}
|
|
19
|
+
/** Props passed to the input toolbar render function. */
|
|
20
|
+
export interface PlanModeViewInputToolbarProps {
|
|
21
|
+
value: string;
|
|
22
|
+
onChange: (text: string) => void;
|
|
23
|
+
onSend: () => void;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface CurrentUser {
|
|
27
|
+
id: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
avatar?: string;
|
|
30
|
+
/** Optional: full author shape for the message-group renderer (givenName, familyName, username, etc.) */
|
|
31
|
+
givenName?: string;
|
|
32
|
+
familyName?: string;
|
|
33
|
+
fullName?: string;
|
|
34
|
+
username?: string;
|
|
35
|
+
email?: string;
|
|
36
|
+
picture?: string | null;
|
|
37
|
+
alias?: any[];
|
|
38
|
+
tokens?: any[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Props the base passes to the injected message-group renderer (`MessageGroupComponent`).
|
|
42
|
+
* Mirrors the shape consumed by richer renderers (e.g. messenger-box's
|
|
43
|
+
* `ModernMessageGroupComponent`) so they can be dropped in directly.
|
|
44
|
+
*/
|
|
45
|
+
export interface MessageGroupRenderProps {
|
|
46
|
+
/** One post group to render (the base passes a single mapped post per group). */
|
|
47
|
+
messages: any[];
|
|
48
|
+
currentUser: any;
|
|
49
|
+
onOpen?: (element?: any) => void;
|
|
50
|
+
onMessageClick?: (msg: any) => void;
|
|
51
|
+
isDesktopView?: boolean;
|
|
52
|
+
isSmallScreen?: boolean;
|
|
53
|
+
showAuthorName?: boolean;
|
|
54
|
+
showAvatar?: boolean;
|
|
55
|
+
showTimestamp?: boolean;
|
|
56
|
+
sandboxErrors?: any[];
|
|
57
|
+
currentFiles?: Record<string, string>;
|
|
58
|
+
onFixError?: (errorMessage: string) => Promise<void>;
|
|
59
|
+
showCopyDownloadOnCodeBlock?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/** The injectable message-group renderer. Defaults to a plain-text bubble renderer. */
|
|
62
|
+
export type MessageGroupComponentType = React.ComponentType<MessageGroupRenderProps>;
|
|
63
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/messages-container-ui/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;;;GAIG;AAEH,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAC1B,6GAA6G;IAC7G,kBAAkB,CAAC,EAAE,GAAG,CAAC;IACzB,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,yDAAyD;AACzD,MAAM,WAAW,6BAA6B;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yGAAyG;IACzG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IACd,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACpC,iFAAiF;IACjF,QAAQ,EAAE,GAAG,EAAE,CAAC;IAChB,WAAW,EAAE,GAAG,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,GAAG,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACzC;AAED,uFAAuF;AACvF,MAAM,MAAM,yBAAyB,GAAG,KAAK,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{MessagesContainerUI}from'./components/messages-container-ui/MessagesContainerUI.js';export{PlanModeView,defaultPlanMessageToPost}from'./components/messages-container-ui/PlanModeView.js';export{DefaultMessageGroup}from'./components/messages-container-ui/DefaultMessageGroup.js';export{DefaultInputToolBar}from'./components/messages-container-ui/DefaultInputToolBar.js';//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/lib/routes.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@admin-layout/tailwind-chat-pro",
|
|
3
|
+
"version": "12.2.4-alpha.76",
|
|
4
|
+
"description": "Customizable base chat / messages container UI (plan mode). The message renderer is injectable, so consumers plug in their own message-group component.",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "CDMBase LLC",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "lib/index.js",
|
|
9
|
+
"module": "lib/index.js",
|
|
10
|
+
"typings": "lib/index.d.ts",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "yarn build:clean && yarn build:lib",
|
|
13
|
+
"build:clean": "rimraf lib",
|
|
14
|
+
"build:lib": "rollup -c rollup.config.mjs",
|
|
15
|
+
"build:lib:watch": "yarn build:lib -- --watch",
|
|
16
|
+
"jest": "./node_modules/.bin/jest",
|
|
17
|
+
"prepublish": "yarn build",
|
|
18
|
+
"test": "cross-env ENV_FILE=../../config/test/test.env jest",
|
|
19
|
+
"test:debug": "npm test -- --runInBand",
|
|
20
|
+
"test:watch": "npm test -- --watch",
|
|
21
|
+
"watch": "yarn build:lib:watch"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@admin-layout/tailwind-ui": "12.2.4-alpha.72",
|
|
25
|
+
"clsx": "^2.1.1"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"common": "12.2.4-alpha.72"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@admin-layout/tailwind-ui": "12.2.4-alpha.72",
|
|
32
|
+
"common": "12.2.4-alpha.72",
|
|
33
|
+
"react": ">=16.14.0"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"gitHead": "fbcea85d7ba6ebd143bf9f82a6d6cc2baa21ffb2",
|
|
39
|
+
"typescript": {
|
|
40
|
+
"definition": "lib/index.d.ts"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createRollupConfig } from '../../../rollup.config.base.mjs';
|
|
2
|
+
|
|
3
|
+
const additionalPlugins = [];
|
|
4
|
+
|
|
5
|
+
export default (commandLineArgs) => {
|
|
6
|
+
const isWatchMode = commandLineArgs.watch;
|
|
7
|
+
return [
|
|
8
|
+
createRollupConfig(
|
|
9
|
+
{
|
|
10
|
+
input: ['src/index.ts'],
|
|
11
|
+
plugins: [
|
|
12
|
+
...additionalPlugins,
|
|
13
|
+
],
|
|
14
|
+
output: [
|
|
15
|
+
{
|
|
16
|
+
dir: 'lib',
|
|
17
|
+
format: 'es',
|
|
18
|
+
name: 'tailwind-chat-pro',
|
|
19
|
+
compact: true,
|
|
20
|
+
exports: 'named',
|
|
21
|
+
sourcemap: true,
|
|
22
|
+
preserveModules: true,
|
|
23
|
+
chunkFileNames: '[name]-[hash].[format].js',
|
|
24
|
+
globals: { react: 'React' },
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
isWatchMode,
|
|
30
|
+
generateRoutesJSON: true,
|
|
31
|
+
},
|
|
32
|
+
),
|
|
33
|
+
];
|
|
34
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './messages-container-ui';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { InputToolBar } from '@admin-layout/tailwind-ui';
|
|
3
|
+
import type { PlanModeViewInputToolbarProps } from './types';
|
|
4
|
+
|
|
5
|
+
export interface DefaultInputToolBarProps extends PlanModeViewInputToolbarProps {
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
/** When true, the send button shows a stop affordance (wired to onStop). */
|
|
8
|
+
isLoading?: boolean;
|
|
9
|
+
onStop?: () => void;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* DefaultInputToolBar — the input composer used when no `renderInputToolbar` is
|
|
15
|
+
* provided. It wraps `@admin-layout/tailwind-ui`'s `InputToolBar` (the shared
|
|
16
|
+
* "ai-tool-box") wired to the base's toolbar props: a built-in textarea
|
|
17
|
+
* (Enter sends, Shift+Enter newlines) plus the mic/send/stop button.
|
|
18
|
+
*
|
|
19
|
+
* Consumers that need the richer composer (mode switcher, templates, attachments,
|
|
20
|
+
* project settings, …) pass their own `renderInputToolbar` instead.
|
|
21
|
+
*/
|
|
22
|
+
export const DefaultInputToolBar: React.FC<DefaultInputToolBarProps> = ({
|
|
23
|
+
value,
|
|
24
|
+
onChange,
|
|
25
|
+
onSend,
|
|
26
|
+
disabled = false,
|
|
27
|
+
placeholder = 'Message',
|
|
28
|
+
isLoading = false,
|
|
29
|
+
onStop,
|
|
30
|
+
className,
|
|
31
|
+
}) => {
|
|
32
|
+
const hasContent = value.trim().length > 0;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<InputToolBar
|
|
36
|
+
className={className}
|
|
37
|
+
inputConfig={{
|
|
38
|
+
value,
|
|
39
|
+
onChange: (e) => onChange(e.target.value),
|
|
40
|
+
placeholder,
|
|
41
|
+
disabled,
|
|
42
|
+
onKeyDown: (e) => {
|
|
43
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
if (hasContent && !disabled && !isLoading) onSend();
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
}}
|
|
49
|
+
micSendButton={{
|
|
50
|
+
hasContent,
|
|
51
|
+
onSend,
|
|
52
|
+
onMic: () => {
|
|
53
|
+
/* voice input not wired in the base default */
|
|
54
|
+
},
|
|
55
|
+
disabled,
|
|
56
|
+
isLoading,
|
|
57
|
+
onStop: isLoading ? onStop : undefined,
|
|
58
|
+
}}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default DefaultInputToolBar;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import type { MessageGroupRenderProps } from './types';
|
|
4
|
+
|
|
5
|
+
const ASSISTANT_BUBBLE_BG = 'bg-white';
|
|
6
|
+
const USER_BUBBLE_BG = 'bg-indigo-50';
|
|
7
|
+
const BORDER_COLOR = 'border-gray-200';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* DefaultMessageGroup — the base renderer used when no `MessageGroupComponent`
|
|
11
|
+
* is injected. Renders the post's text in a left/right aligned bubble with an
|
|
12
|
+
* optional author name, avatar and timestamp. Whitespace is preserved so
|
|
13
|
+
* plain-text replies read naturally.
|
|
14
|
+
*
|
|
15
|
+
* Consumers that need rich rendering (markdown, code blocks, media/travel/
|
|
16
|
+
* workflow widget cards, …) inject their own component via
|
|
17
|
+
* `MessagesContainerUI`'s `MessageGroupComponent` prop — e.g. messenger-box's
|
|
18
|
+
* `ModernMessageGroupComponent`.
|
|
19
|
+
*/
|
|
20
|
+
export const DefaultMessageGroup: React.FC<MessageGroupRenderProps> = ({
|
|
21
|
+
messages,
|
|
22
|
+
onMessageClick,
|
|
23
|
+
showAuthorName = false,
|
|
24
|
+
showAvatar = false,
|
|
25
|
+
showTimestamp = false,
|
|
26
|
+
}) => {
|
|
27
|
+
const post = messages?.[0];
|
|
28
|
+
if (!post) return null;
|
|
29
|
+
|
|
30
|
+
const role = post?.propsConfiguration?.contents?.role;
|
|
31
|
+
const isUser = role === 'USER' || role === 'user' || post?.author?.isCurrentUser === true;
|
|
32
|
+
const text: string = typeof post?.message === 'string' ? post.message : '';
|
|
33
|
+
const author = post?.author ?? {};
|
|
34
|
+
const name: string = author.fullName || author.givenName || author.username || (isUser ? 'You' : 'Assistant');
|
|
35
|
+
const picture: string | null = author.picture ?? null;
|
|
36
|
+
const created = post?.createdAt ? new Date(post.createdAt) : null;
|
|
37
|
+
const timeLabel = created && !Number.isNaN(created.getTime()) ? created.toLocaleTimeString() : '';
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className={clsx('flex w-full', isUser ? 'justify-end' : 'justify-start')}>
|
|
41
|
+
<div className={clsx('flex max-w-[85%] gap-2', isUser ? 'flex-row-reverse' : 'flex-row')}>
|
|
42
|
+
{showAvatar && (
|
|
43
|
+
<div className="flex-shrink-0">
|
|
44
|
+
{picture ? (
|
|
45
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
46
|
+
<img src={picture} alt={name} className="w-7 h-7 rounded-full object-cover" />
|
|
47
|
+
) : (
|
|
48
|
+
<div className="w-7 h-7 rounded-full bg-gray-200 flex items-center justify-center text-xs font-medium text-gray-600">
|
|
49
|
+
{name.charAt(0).toUpperCase()}
|
|
50
|
+
</div>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
)}
|
|
54
|
+
<div className={clsx('min-w-0', isUser ? 'text-right' : 'text-left')}>
|
|
55
|
+
{showAuthorName && <div className="mb-0.5 text-xs font-medium text-gray-500">{name}</div>}
|
|
56
|
+
<div
|
|
57
|
+
onClick={onMessageClick ? () => onMessageClick(post) : undefined}
|
|
58
|
+
className={clsx(
|
|
59
|
+
'inline-block rounded-2xl px-4 py-2.5 text-[15px] leading-relaxed text-gray-900',
|
|
60
|
+
'whitespace-pre-wrap break-words border',
|
|
61
|
+
BORDER_COLOR,
|
|
62
|
+
isUser ? USER_BUBBLE_BG : ASSISTANT_BUBBLE_BG,
|
|
63
|
+
onMessageClick && 'cursor-pointer',
|
|
64
|
+
)}
|
|
65
|
+
>
|
|
66
|
+
{text}
|
|
67
|
+
</div>
|
|
68
|
+
{showTimestamp && timeLabel && <div className="mt-0.5 text-[11px] text-gray-400">{timeLabel}</div>}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export default DefaultMessageGroup;
|