Skip to content

Commit 3a8e442

Browse files
committed
feat(ai-chat-log): add new components
1 parent 8ee187d commit 3a8e442

File tree

4 files changed

+204
-1
lines changed

4 files changed

+204
-1
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { BoxElementProps } from "@twilio-paste/box";
2+
import { Box, safelySpreadBoxProps } from "@twilio-paste/box";
3+
import type { HTMLPasteProps } from "@twilio-paste/types";
4+
import * as React from "react";
5+
6+
export interface AIChatMessageSourceProps extends HTMLPasteProps<"div"> {
7+
children?: React.ReactNode;
8+
/**
9+
* Overrides the default element name to apply unique styles with the Customization Provider
10+
*
11+
* @default "AI_CHAT_MESSAGE"
12+
* @type {BoxProps["element"]}
13+
* @memberof AIChatMessageSourceProps
14+
*/
15+
element?: BoxElementProps["element"];
16+
}
17+
18+
export const AIChatMessageSource = React.forwardRef<HTMLDivElement, AIChatMessageSourceProps>(
19+
({ children, element = "AI_CHAT_MESSAGE_SOURCE", ...props }, ref) => {
20+
return (
21+
<Box
22+
as="sup"
23+
ref={ref}
24+
element={element}
25+
verticalAlign="inherit"
26+
fontSize="inherit"
27+
paddingX="space10"
28+
color="colorTextWeak"
29+
{...safelySpreadBoxProps(props)}
30+
>
31+
[{children}]
32+
</Box>
33+
);
34+
},
35+
);
36+
37+
AIChatMessageSource.displayName = "AIChatMessageSource";
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Anchor } from "@twilio-paste/anchor";
2+
import type { BoxElementProps } from "@twilio-paste/box";
3+
import { Box, safelySpreadBoxProps } from "@twilio-paste/box";
4+
import type { HTMLPasteProps } from "@twilio-paste/types";
5+
import * as React from "react";
6+
7+
export interface AIChatMessageSourceLinkProps extends HTMLPasteProps<"div"> {
8+
children: React.ReactNode;
9+
/**
10+
* Overrides the default element name to apply unique styles with the Customization Provider
11+
*
12+
* @default "AI_CHAT_MESSAGE"
13+
* @type {BoxProps["element"]}
14+
* @memberof AIChatMessageSourceLinkProps
15+
*/
16+
element?: BoxElementProps["element"];
17+
/**
18+
* The item number of the source link in the AI chat message.
19+
*
20+
* @type {string}
21+
* @memberof AIChatMessageSourceLinkProps
22+
* @example "1"
23+
*/
24+
number: string;
25+
/**
26+
* The source link URL in the AI chat message.
27+
*
28+
* @type {string}
29+
* @memberof AIChatMessageSourceLinkProps
30+
* @example "https://example.com"
31+
*/
32+
url: string;
33+
}
34+
35+
export const AIChatMessageSourceLink = React.forwardRef<HTMLDivElement, AIChatMessageSourceLinkProps>(
36+
({ children, number, url, element = "AI_CHAT_MESSAGE_SOURCE_LINK", ...props }, ref) => {
37+
return (
38+
<Box
39+
ref={ref}
40+
element={element}
41+
verticalAlign="inherit"
42+
fontSize="inherit"
43+
color="colorTextWeak"
44+
{...safelySpreadBoxProps(props)}
45+
>
46+
[{number}]{" "}
47+
<Box as="span" marginLeft="space10">
48+
{children}
49+
</Box>
50+
<Anchor href={url} showExternal marginLeft="space10">
51+
Source with url
52+
</Anchor>
53+
</Box>
54+
);
55+
},
56+
);
57+
58+
AIChatMessageSourceLink.displayName = "AIChatMessageSourceLink";

packages/paste-core/components/ai-chat-log/src/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,8 @@ export { AIChatLogger } from "./AIChatLogger";
2121
export type { AIChatLoggerProps } from "./AIChatLogger";
2222

2323
export type { AIMessageVariants } from "./AIMessageContext";
24+
25+
export { AIChatMessageSource } from "./AIChatMessageSource";
26+
export type { AIChatMessageSourceProps } from "./AIChatMessageSource";
27+
export { AIChatMessageSourceLink } from "./AIChatMessageSourceLink";
28+
export type { AIChatMessageSourceLinkProps } from "./AIChatMessageSourceLink";

packages/paste-core/components/ai-chat-log/stories/aiChatLog.stories.tsx

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ import { RefreshIcon } from "@twilio-paste/icons/esm/RefreshIcon";
1111
import { SendIcon } from "@twilio-paste/icons/esm/SendIcon";
1212
import { ThumbsDownIcon } from "@twilio-paste/icons/esm/ThumbsDownIcon";
1313
import { ThumbsUpIcon } from "@twilio-paste/icons/esm/ThumbsUpIcon";
14-
import { UserIcon } from "@twilio-paste/icons/esm/UserIcon";
14+
import {
15+
SummaryDetail,
16+
SummaryDetailContent,
17+
SummaryDetailHeading,
18+
SummaryDetailHeadingContent,
19+
SummaryDetailToggleButton,
20+
} from "@twilio-paste/summary-detail";
1521
import { Text } from "@twilio-paste/text";
1622
import { useTheme } from "@twilio-paste/theme";
1723
import * as React from "react";
@@ -25,6 +31,8 @@ import {
2531
AIChatMessageAuthor,
2632
AIChatMessageBody,
2733
AIChatMessageLoading,
34+
AIChatMessageSource,
35+
AIChatMessageSourceLink,
2836
} from "../src";
2937

3038
export default {
@@ -234,6 +242,101 @@ export const ExampleAIChatLogAgent = (): React.ReactNode => {
234242
</>
235243
);
236244
};
245+
246+
export const ExampleAIChatLogSources = (): React.ReactNode => {
247+
return (
248+
<>
249+
<AIChatLog>
250+
<AIChatMessage variant="user">
251+
<AIChatMessageBody timestamp="3:42pm">
252+
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Deserunt delectus fuga, necessitatibus eligendi
253+
iure adipisci facilis exercitationem officiis dolorem laborum, ex fugiat quisquam itaque, earum sit nesciunt
254+
impedit repellat assumenda.
255+
</AIChatMessageBody>
256+
</AIChatMessage>
257+
258+
<AIChatEvent>
259+
<Text color="colorTextWeak" fontSize="fontSize20" fontWeight="fontWeightSemibold" as="span">
260+
Agent
261+
</Text>
262+
has joined the chat・3:43pm
263+
</AIChatEvent>
264+
265+
<AIChatMessage variant="agent">
266+
<AIChatMessageAuthor avatarIcon={CommunityIcon} aria-label="Agent said">
267+
Agent Name
268+
</AIChatMessageAuthor>
269+
<AIChatMessageBody timestamp="3:44pm">
270+
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Deserunt delectus fuga, necessitatibus eligendi
271+
iure adipisci facilis exercitationem officiis dolorem laborum<AIChatMessageSource>1</AIChatMessageSource>,
272+
ex fugiat quisquam itaque, earum sit nesciunt impedit repellat assumenda.
273+
<AIChatMessageSource>2</AIChatMessageSource>
274+
</AIChatMessageBody>
275+
<SummaryDetail>
276+
<SummaryDetailHeading>
277+
<SummaryDetailToggleButton aria-label="BOOP" />
278+
<SummaryDetailHeadingContent>
279+
<Text as="p" fontWeight="fontWeightSemibold">
280+
Sources
281+
</Text>
282+
</SummaryDetailHeadingContent>
283+
</SummaryDetailHeading>
284+
<SummaryDetailContent>
285+
<Box display="flex" flexDirection="column" rowGap="space20">
286+
<AIChatMessageSourceLink number="1" url="#">
287+
Source title
288+
</AIChatMessageSourceLink>
289+
<AIChatMessageSourceLink number="2" url="#">
290+
Source title
291+
</AIChatMessageSourceLink>
292+
<AIChatMessageSourceLink number="3" url="#">
293+
Source title
294+
</AIChatMessageSourceLink>
295+
</Box>
296+
</SummaryDetailContent>
297+
</SummaryDetail>
298+
<AIChatMessageActionGroup>
299+
<AIChatMessageActionCard aria-label="Feedback form">
300+
Is this helpful?
301+
<Button variant="secondary_icon" size="reset" aria-label="this is a helpful response">
302+
<ThumbsUpIcon decorative={false} title="like result" />
303+
</Button>
304+
<Button variant="secondary_icon" size="reset" aria-label="this is not a helpful response">
305+
<ThumbsDownIcon decorative={false} title="dislike result" />
306+
</Button>
307+
</AIChatMessageActionCard>
308+
<AIChatMessageActionCard aria-label="Rewrite and copy buttons">
309+
<Button variant="secondary_icon" size="reset">
310+
<RefreshIcon decorative />
311+
Rewrite
312+
</Button>
313+
<Button variant="secondary_icon" size="reset">
314+
<CopyIcon decorative />
315+
Copy
316+
</Button>
317+
</AIChatMessageActionCard>
318+
</AIChatMessageActionGroup>
319+
</AIChatMessage>
320+
</AIChatLog>
321+
<ChatComposer
322+
config={{
323+
namespace: "customer-chat",
324+
onError: (e) => {
325+
throw e;
326+
},
327+
}}
328+
placeholder="Chat text"
329+
ariaLabel="A placeholder chat composer"
330+
>
331+
<Box position="absolute" top="space30" right="space30">
332+
<Button variant="primary_icon" size="reset">
333+
<SendIcon decorative={false} title="Send message" />
334+
</Button>
335+
</Box>
336+
</ChatComposer>
337+
</>
338+
);
339+
};
237340
export const ExampleFullScreenAIChatLog = (): React.ReactNode => {
238341
return (
239342
<>

0 commit comments

Comments
 (0)