diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index 7c6c6bc585..216bcfd9c6 100644 --- a/.codesandbox/ci.json +++ b/.codesandbox/ci.json @@ -5,6 +5,7 @@ "/packages/paste-icons", "/packages/paste-core/core-bundle", "/packages/paste-core/components/account-switcher", + "/packages/paste-core/components/ai-chat-log", "/packages/paste-core/components/alert", "/packages/paste-core/components/alert-dialog", "/packages/paste-core/components/anchor", diff --git a/packages/paste-codemods/tools/.cache/mappings.json b/packages/paste-codemods/tools/.cache/mappings.json index 395930baac..aa05274a43 100644 --- a/packages/paste-codemods/tools/.cache/mappings.json +++ b/packages/paste-codemods/tools/.cache/mappings.json @@ -6,6 +6,13 @@ "AccountSwitcherItemRadio": "@twilio-paste/core/account-switcher", "AccountSwitcherSeparator": "@twilio-paste/core/account-switcher", "useAccountSwitcherState": "@twilio-paste/core/account-switcher", + "AIChatLog": "@twilio-paste/core/ai-chat-log", + "AIChatLogger": "@twilio-paste/core/ai-chat-log", + "AIChatMessage": "@twilio-paste/core/ai-chat-log", + "AIChatMessageContent": "@twilio-paste/core/ai-chat-log", + "AIChatMessageMeta": "@twilio-paste/core/ai-chat-log", + "AIChatMessageMetaItem": "@twilio-paste/core/ai-chat-log", + "useAIChatLogger": "@twilio-paste/core/ai-chat-log", "Alert": "@twilio-paste/core/alert", "AlertDialog": "@twilio-paste/core/alert-dialog", "Anchor": "@twilio-paste/core/anchor", diff --git a/packages/paste-core/components/ai-log/__tests__/index.spec.tsx b/packages/paste-core/components/ai-chat-log/__tests__/index.spec.tsx similarity index 100% rename from packages/paste-core/components/ai-log/__tests__/index.spec.tsx rename to packages/paste-core/components/ai-chat-log/__tests__/index.spec.tsx diff --git a/packages/paste-core/components/ai-log/build.js b/packages/paste-core/components/ai-chat-log/build.js similarity index 100% rename from packages/paste-core/components/ai-log/build.js rename to packages/paste-core/components/ai-chat-log/build.js diff --git a/packages/paste-core/components/ai-log/package.json b/packages/paste-core/components/ai-chat-log/package.json similarity index 96% rename from packages/paste-core/components/ai-log/package.json rename to packages/paste-core/components/ai-chat-log/package.json index 8b487c5aef..1f34742229 100644 --- a/packages/paste-core/components/ai-log/package.json +++ b/packages/paste-core/components/ai-chat-log/package.json @@ -1,5 +1,5 @@ { - "name": "@twilio-paste/ai-log", + "name": "@twilio-paste/ai-chat-log", "version": "0.0.0", "category": "data display", "status": "production", @@ -53,7 +53,7 @@ "@types/react-dom": "^18.0.10", "react": "^18.0.0", "react-dom": "^18.0.0", - "tsx": "^3.12.10", + "tsx": "^4.0.0", "typescript": "^4.9.4" } } diff --git a/packages/paste-core/components/ai-log/src/AIChatLog.tsx b/packages/paste-core/components/ai-chat-log/src/AIChatLog.tsx similarity index 94% rename from packages/paste-core/components/ai-log/src/AIChatLog.tsx rename to packages/paste-core/components/ai-chat-log/src/AIChatLog.tsx index 23a31253a9..baf90b4e59 100644 --- a/packages/paste-core/components/ai-log/src/AIChatLog.tsx +++ b/packages/paste-core/components/ai-chat-log/src/AIChatLog.tsx @@ -15,7 +15,7 @@ export interface AIChatLogProps extends HTMLPasteProps<"div"> { } export const AIChatLog = React.forwardRef( - ({ element = "AI_LOG", children, ...props }, ref) => { + ({ element = "AI_CHAT_LOG", children, ...props }, ref) => { return ( { } export const AIChatMessage = React.forwardRef( - ({ children, element = "CHAT_MESSAGE", ...props }, ref) => { + ({ children, element = "AI_CHAT_MESSAGE", ...props }, ref) => { return ( { +export interface AIChatMessageActionsProps extends HTMLPasteProps<"div"> { children: NonNullable; - variant: "author" | "timestamp"; /** * Overrides the default element name to apply unique styles with the Customization Provider * @@ -16,18 +15,10 @@ export interface AIChatMessageMetaItemProps extends HTMLPasteProps<"div"> { element?: BoxElementProps["element"]; } -const variantStyles = { - author: { - color: "colorText", - lineHeight: "lineHeight50", - fontSize: "fontSize40", - }, - timestamp: {}, -}; - -export const AIChatMessageMetaItem = React.forwardRef( - ({ children, element = "CHAT_MESSAGE_META_ITEM", ...props }, ref) => ( +export const AIChatMessageActions = React.forwardRef( + ({ children, element = "AI_CHAT_MESSAGE_ACTIONS", ...props }, ref) => ( {children} ), ); -AIChatMessageMetaItem.displayName = "AIChatMessageMetaItem"; +AIChatMessageActions.displayName = "AIChatMessageActions"; diff --git a/packages/paste-core/components/ai-chat-log/src/AIChatMessageBody.tsx b/packages/paste-core/components/ai-chat-log/src/AIChatMessageBody.tsx new file mode 100644 index 0000000000..1ed4a4244f --- /dev/null +++ b/packages/paste-core/components/ai-chat-log/src/AIChatMessageBody.tsx @@ -0,0 +1,59 @@ +import { Box, safelySpreadBoxProps } from "@twilio-paste/box"; +import type { BoxElementProps } from "@twilio-paste/box"; +import type { ThemeShape } from "@twilio-paste/theme"; +import type { HTMLPasteProps } from "@twilio-paste/types"; +import * as React from "react"; + +const Variants = { + default: { + fontSize: "fontSize30" as ThemeShape["fontSizes"], + lineHeight: "lineHeight30" as ThemeShape["lineHeights"], + }, + fullScreen: { + fontSize: "fontSize40" as ThemeShape["fontSizes"], + lineHeight: "lineHeight40" as ThemeShape["lineHeights"], + }, +}; + +export interface AIChatMessageBodyProps extends HTMLPasteProps<"div"> { + children?: React.ReactNode; + /** + * Overrides the default element name to apply unique styles with the Customization Provider + * + * @default "CHAT_BUBBLE" + * @type {BoxProps["element"]} + * @memberof AIChatBubbleProps + */ + element?: BoxElementProps["element"]; + /** + * Override the font size for full screen experiences. + * + * @default "CHAT_BUBBLE" + * @type {"default" | "fullScreen"} + * @memberof AIChatBubbleProps + */ + variant?: "default" | "fullScreen"; +} + +export const AIChatMessageBody = React.forwardRef( + ({ children, variant = "default", element = "AI_CHAT_MESSAGE_BODY", ...props }, ref) => { + return ( + + {children} + + ); + }, +); + +AIChatMessageBody.displayName = "AIChatMessageBody"; diff --git a/packages/paste-core/components/ai-chat-log/src/AIChatMessageFeedback.tsx b/packages/paste-core/components/ai-chat-log/src/AIChatMessageFeedback.tsx new file mode 100644 index 0000000000..035406ce6a --- /dev/null +++ b/packages/paste-core/components/ai-chat-log/src/AIChatMessageFeedback.tsx @@ -0,0 +1,67 @@ +import { Box, safelySpreadBoxProps } from "@twilio-paste/box"; +import type { BoxElementProps } from "@twilio-paste/box"; +import { Button } from "@twilio-paste/button"; +import { ThumbsDownIcon } from "@twilio-paste/icons/esm/ThumbsDownIcon"; +import { ThumbsUpIcon } from "@twilio-paste/icons/esm/ThumbsUpIcon"; +import type { HTMLPasteProps } from "@twilio-paste/types"; +import * as React from "react"; + +export interface AIChatMessageFeedbackProps extends HTMLPasteProps<"div"> { + children?: never; + /** + * Overrides the default element name to apply unique styles with the Customization Provider + * + * @default "CHAT_MESSAGE_META_ITEM" + * @type {BoxProps["element"]} + * @memberof AIChatMessageMetaItemProps + */ + element?: BoxElementProps["element"]; + label?: string; + i18nLikeLabel?: string; + i18nDislikeLabel?: string; + onLike: () => void; + onDislike: () => void; +} + +export const AIChatMessageFeedback = React.forwardRef( + ( + { + label = "Is this helpful?", + i18nLikeLabel = "Like result", + i18nDislikeLabel = "Dislike result", + onLike, + onDislike, + element = "AI_CHAT_MESSAGE_FEEDBACK", + ...props + }, + ref, + ) => ( + + {label} + + + + ), +); + +AIChatMessageFeedback.displayName = "AIChatMessageFeedback"; diff --git a/packages/paste-core/components/ai-chat-log/src/AIChatMessageLoading.tsx b/packages/paste-core/components/ai-chat-log/src/AIChatMessageLoading.tsx new file mode 100644 index 0000000000..67d468ae9e --- /dev/null +++ b/packages/paste-core/components/ai-chat-log/src/AIChatMessageLoading.tsx @@ -0,0 +1,56 @@ +import { Box, safelySpreadBoxProps } from "@twilio-paste/box"; +import type { BoxElementProps } from "@twilio-paste/box"; +import { Button } from "@twilio-paste/button"; +import { StopIcon } from "@twilio-paste/icons/esm/StopIcon"; +import { ScreenReaderOnly } from "@twilio-paste/screen-reader-only"; +import { SkeletonLoader } from "@twilio-paste/skeleton-loader"; +import type { HTMLPasteProps } from "@twilio-paste/types"; +import * as React from "react"; + +const clampedRandom = (min: number, max: number): number => { + return Math.min(Math.max(min, Math.random() * max), max); +}; +export interface AIChatMessageLoadingProps extends HTMLPasteProps<"div"> { + children?: never; + /** + * Overrides the default element name to apply unique styles with the Customization Provider + * + * @default "CHAT_MESSAGE" + * @type {BoxProps["element"]} + * @memberof ChatMessageProps + */ + element?: BoxElementProps["element"]; + onStopLoading?: () => void; +} + +export const AIChatMessageLoading = React.forwardRef( + ({ onStopLoading, element = "AI_CHAT_MESSAGE_LOADING", ...props }, ref) => { + const widths = React.useRef([clampedRandom(40, 75), clampedRandom(65, 100), clampedRandom(55, 80)]).current; + + return ( + + + + + {onStopLoading ? ( + + + + ) : null} + + ); + }, +); + +AIChatMessageLoading.displayName = "AIChatMessageLoading"; diff --git a/packages/paste-core/components/ai-log/src/AIChatMessageMeta.tsx b/packages/paste-core/components/ai-chat-log/src/AIChatMessageMeta.tsx similarity index 94% rename from packages/paste-core/components/ai-log/src/AIChatMessageMeta.tsx rename to packages/paste-core/components/ai-chat-log/src/AIChatMessageMeta.tsx index dd19c55fcc..188a865be7 100644 --- a/packages/paste-core/components/ai-log/src/AIChatMessageMeta.tsx +++ b/packages/paste-core/components/ai-chat-log/src/AIChatMessageMeta.tsx @@ -23,7 +23,7 @@ export interface AIChatMessageMetaProps extends HTMLPasteProps<"div"> { } export const AIChatMessageMeta = React.forwardRef( - ({ children, element = "CHAT_MESSAGE_META", ...props }, ref) => { + ({ children, element = "AI_CHAT_MESSAGE_META", ...props }, ref) => { return ( { + return ( + + + + + You + + + Lorem ipsum dolor, sit amet consectetur adipisicing elit. Deserunt delectus fuga, necessitatibus eligendi iure + adipisci facilis exercitationem officiis dolorem laborum, ex fugiat quisquam itaque, earum sit nesciunt + impedit repellat assumenda. + + + + + + + AI Bot + + + Lorem ipsum dolor, sit amet consectetur adipisicing elit. Deserunt delectus fuga, necessitatibus eligendi iure + adipisci facilis exercitationem officiis dolorem laborum, ex fugiat quisquam itaque, earum sit nesciunt + impedit repellat assumenda. + + + + + + + + + + {}} onDislike={() => {}} /> + + + + + + + You + + + Lorem ipsum dolor, sit amet consectetur adipisicing elit. Deserunt delectus fuga, necessitatibus eligendi iure + adipisci facilis exercitationem officiis dolorem laborum, ex fugiat quisquam itaque, earum sit nesciunt + impedit repellat assumenda. + + + + + + + AI Bot + + + {}} /> + + + + ); +}; diff --git a/packages/paste-core/components/ai-chat-log/stories/parts.stories.tsx b/packages/paste-core/components/ai-chat-log/stories/parts.stories.tsx new file mode 100644 index 0000000000..ad436df8d4 --- /dev/null +++ b/packages/paste-core/components/ai-chat-log/stories/parts.stories.tsx @@ -0,0 +1,106 @@ +import * as React from "react"; + +import { Avatar } from "@twilio-paste/avatar"; +import { Box } from "@twilio-paste/box"; +import { Button } from "@twilio-paste/button"; +import { ButtonGroup } from "@twilio-paste/button-group"; +import { InlineCode } from "@twilio-paste/inline-code"; +import { ArtificialIntelligenceIcon } from "@twilio-paste/icons/esm/ArtificialIntelligenceIcon"; +import { useUID } from "@twilio-paste/uid-library"; + +import { Text } from "@twilio-paste/text"; + +import { + AIChatLog, + AIChatMessage, + AIChatMessageBody, + AIChatMessageFeedback, + AIChatMessageLoading, + AIChatMessageMeta, +} from "../src"; + +// eslint-disable-next-line import/no-default-export +export default { + title: "Components/AI Chat Log/Parts", + component: AIChatLog, +}; + + + +export const MessageBody = (): React.ReactNode => { + return ( + + Use variant="default" when the AI Chat Log is inside a small container. + Use variant="fullSCreen" when the AI Chat Log is a full screen experience. + + ); +}; + + +export const MessageBodyWithParagraphs = (): React.ReactNode => { + return ( + + +

Test

+

Test

+
+ + +

Test

+

Test

+
+
+ ); +}; + + + + + + +export const Loading = (): React.ReactNode => { + return ( +
+

Pssst! The three rows have dynamic widths. Refresh to see it in action!

+ +
+ ); +}; + +export const LoadingStopLoading = (): React.ReactNode => { + const [loading, setLoading] = React.useState(true); + return ( +
+ {loading ? ( + { + setLoading(false); + }} + /> + ) : ( + "Aborted loading!" + )} +
+ ); +}; +LoadingStopLoading.storyName = "Loading with stop button"; + +export const Feedback = (): React.ReactNode => { + /* eslint-disable no-alert */ + return ( + + alert("Like + 1")} onDislike={() => alert("Like - 1")} /> + + ); + /* eslint-enable no-alert */ +}; + +export const FeedbackCustomLabels = (): React.ReactNode => { + /* eslint-disable no-alert */ + return ( + + alert("Like + 1")} onDislike={() => alert("Like - 1")} /> + + ); + /* eslint-enable no-alert */ +}; diff --git a/packages/paste-core/components/ai-log/tsconfig.json b/packages/paste-core/components/ai-chat-log/tsconfig.json similarity index 100% rename from packages/paste-core/components/ai-log/tsconfig.json rename to packages/paste-core/components/ai-chat-log/tsconfig.json diff --git a/packages/paste-core/components/ai-log/src/AIChatMessageContent.tsx b/packages/paste-core/components/ai-log/src/AIChatMessageContent.tsx deleted file mode 100644 index 0958389f62..0000000000 --- a/packages/paste-core/components/ai-log/src/AIChatMessageContent.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Box, safelySpreadBoxProps } from "@twilio-paste/box"; -import type { BoxElementProps, BoxStyleProps } from "@twilio-paste/box"; -import type { HTMLPasteProps } from "@twilio-paste/types"; -import * as React from "react"; - -export interface AIChatMessageContentProps extends HTMLPasteProps<"div"> { - children?: React.ReactNode; - /** - * Overrides the default element name to apply unique styles with the Customization Provider - * - * @default "CHAT_BUBBLE" - * @type {BoxProps["element"]} - * @memberof AIChatBubbleProps - */ - element?: BoxElementProps["element"]; -} - -export const AIChatMessageContent = React.forwardRef( - ({ children, element = "CHAT_MESSAGE_CONTENT", ...props }, ref) => { - return ( - - {children} - - ); - }, -); - -AIChatMessageContent.displayName = "AIChatMessageContent"; diff --git a/packages/paste-core/components/ai-log/stories/index.stories.tsx b/packages/paste-core/components/ai-log/stories/index.stories.tsx deleted file mode 100644 index 2f9fc10400..0000000000 --- a/packages/paste-core/components/ai-log/stories/index.stories.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import * as React from "react"; - -import { Avatar } from "@twilio-paste/avatar"; -import { Box } from "@twilio-paste/box"; -import { ArtificialIntelligenceIcon } from "@twilio-paste/icons/esm/ArtificialIntelligenceIcon"; -import { useUID } from "@twilio-paste/uid-library"; -import { AIChatLog, AIChatMessage, AIChatMessageContent, AIChatMessageMeta, AIChatMessageMetaItem } from "../src"; - -// eslint-disable-next-line import/no-default-export -export default { - title: "Components/AI Log", - component: AIChatLog, -}; - -export const Default = (): React.ReactNode => { - const [showButton, setShowButton] = React.useState(true); - const chatBoxUniqueID = useUID(); - return ( - - - - - - - You - - - - Lorem ipsum dolor, sit amet consectetur adipisicing elit. Deserunt delectus fuga, necessitatibus eligendi - iure adipisci facilis exercitationem officiis dolorem laborum, ex fugiat quisquam itaque, earum sit nesciunt - impedit repellat assumenda. - - - 30007 - 30007 - 30007 - - - Was this helpful? - - - - - - - AI Bot - - - - Lorem ipsum dolor, sit amet consectetur adipisicing elit. Deserunt delectus fuga, necessitatibus eligendi - iure adipisci facilis exercitationem officiis dolorem laborum, ex fugiat quisquam itaque, earum sit nesciunt - impedit repellat assumenda. - - - 30007 - 30007 - 30007 - - - Was this helpful? - - - - - ); -}; diff --git a/packages/paste-core/components/chat-log/stories/index.stories.tsx b/packages/paste-core/components/chat-log/stories/index.stories.tsx index a591fa21dc..f2a9688dd2 100644 --- a/packages/paste-core/components/chat-log/stories/index.stories.tsx +++ b/packages/paste-core/components/chat-log/stories/index.stories.tsx @@ -125,8 +125,6 @@ export const ScrollingChatLog: StoryFn = () => { Message failed - - diff --git a/packages/paste-core/core-bundle/.gitignore b/packages/paste-core/core-bundle/.gitignore index 84b80d657b..78137ef542 100644 --- a/packages/paste-core/core-bundle/.gitignore +++ b/packages/paste-core/core-bundle/.gitignore @@ -1,6 +1,7 @@ # Automatically generated from "yarn generate-packages" /dist /account-switcher +/ai-chat-log /alert /alert-dialog /anchor diff --git a/packages/paste-core/core-bundle/package.json b/packages/paste-core/core-bundle/package.json index 546d2e2c41..ae0e41fd64 100644 --- a/packages/paste-core/core-bundle/package.json +++ b/packages/paste-core/core-bundle/package.json @@ -72,6 +72,7 @@ }, "dependencies": { "@twilio-paste/account-switcher": "^3.0.1", + "@twilio-paste/ai-chat-log": "^0.0.0", "@twilio-paste/alert": "^14.1.0", "@twilio-paste/alert-dialog": "^9.2.0", "@twilio-paste/anchor": "^12.1.0", diff --git a/packages/paste-core/core-bundle/side-panel/package.json b/packages/paste-core/core-bundle/side-panel/package.json new file mode 100644 index 0000000000..1a4d6804f8 --- /dev/null +++ b/packages/paste-core/core-bundle/side-panel/package.json @@ -0,0 +1,8 @@ +{ + "name": "@twilio-paste-core/side-panel", + "version": "0.0.0", + "private": true, + "sideEffects": false, + "main": "../dist/side-panel.js", + "types": "../dist/side-panel.d.ts" +} \ No newline at end of file diff --git a/packages/paste-core/core-bundle/src/ai-chat-log.tsx b/packages/paste-core/core-bundle/src/ai-chat-log.tsx new file mode 100644 index 0000000000..4904080312 --- /dev/null +++ b/packages/paste-core/core-bundle/src/ai-chat-log.tsx @@ -0,0 +1 @@ +export * from "@twilio-paste/ai-chat-log"; diff --git a/packages/paste-core/core-bundle/src/index.tsx b/packages/paste-core/core-bundle/src/index.tsx index cdcb49ccd9..a5a0e09f33 100644 --- a/packages/paste-core/core-bundle/src/index.tsx +++ b/packages/paste-core/core-bundle/src/index.tsx @@ -1,4 +1,5 @@ export * from "@twilio-paste/account-switcher"; +export * from "@twilio-paste/ai-chat-log"; export * from "@twilio-paste/alert"; export * from "@twilio-paste/alert-dialog"; export * from "@twilio-paste/anchor"; diff --git a/yarn.lock b/yarn.lock index e21441e8ef..040c21089f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11216,9 +11216,9 @@ __metadata: languageName: unknown linkType: soft -"@twilio-paste/ai-log@workspace:packages/paste-core/components/ai-log": +"@twilio-paste/ai-chat-log@^0.0.0, @twilio-paste/ai-chat-log@workspace:packages/paste-core/components/ai-chat-log": version: 0.0.0-use.local - resolution: "@twilio-paste/ai-log@workspace:packages/paste-core/components/ai-log" + resolution: "@twilio-paste/ai-chat-log@workspace:packages/paste-core/components/ai-chat-log" dependencies: "@twilio-paste/animation-library": ^2.0.0 "@twilio-paste/box": ^10.2.0 @@ -11233,7 +11233,7 @@ __metadata: "@types/react-dom": ^18.0.10 react: ^18.0.0 react-dom: ^18.0.0 - tsx: ^3.12.10 + tsx: ^4.0.0 typescript: ^4.9.4 peerDependencies: "@twilio-paste/animation-library": ^2.0.0 @@ -12231,6 +12231,7 @@ __metadata: resolution: "@twilio-paste/core@workspace:packages/paste-core/core-bundle" dependencies: "@twilio-paste/account-switcher": ^3.0.1 + "@twilio-paste/ai-chat-log": ^0.0.0 "@twilio-paste/alert": ^14.1.0 "@twilio-paste/alert-dialog": ^9.2.0 "@twilio-paste/anchor": ^12.1.0 @@ -41693,7 +41694,7 @@ resolve@^2.0.0-next.3: languageName: node linkType: hard -"source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.21, source-map-support@npm:~0.5.12, source-map-support@npm:~0.5.19, source-map-support@npm:~0.5.20": +"source-map-support@npm:^0.5.16, source-map-support@npm:~0.5.12, source-map-support@npm:~0.5.19, source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" dependencies: @@ -43705,23 +43706,6 @@ resolve@^2.0.0-next.3: languageName: node linkType: hard -"tsx@npm:^3.12.10": - version: 3.14.0 - resolution: "tsx@npm:3.14.0" - dependencies: - esbuild: ~0.18.20 - fsevents: ~2.3.3 - get-tsconfig: ^4.7.2 - source-map-support: ^0.5.21 - dependenciesMeta: - fsevents: - optional: true - bin: - tsx: dist/cli.mjs - checksum: afcef5d9b90b5800cf1ffb749e943f63042d78a4c0d9eef6e13e43f4ecab465d45e2c9812a2c515cbdc2ee913ff1cd01bf5c606a48013dd3ce2214a631b45557 - languageName: node - linkType: hard - "tsx@npm:^4.0.0": version: 4.6.2 resolution: "tsx@npm:4.6.2"