diff --git a/apps/www/components/shadcn/Shadcn.tsx b/apps/www/components/shadcn/Shadcn.tsx index e00866030..5333614fb 100644 --- a/apps/www/components/shadcn/Shadcn.tsx +++ b/apps/www/components/shadcn/Shadcn.tsx @@ -132,20 +132,7 @@ export const Shadcn = () => {
- +
); diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index 81884deea..dc00ebaba 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@assistant-ui/react-ui", - "version": "0.0.8", + "version": "0.0.9", "license": "MIT", "exports": { ".": { diff --git a/packages/react-ui/src/components/assistant-message.tsx b/packages/react-ui/src/components/assistant-message.tsx index d7770a58c..b6f9c4251 100644 --- a/packages/react-ui/src/components/assistant-message.tsx +++ b/packages/react-ui/src/components/assistant-message.tsx @@ -10,6 +10,7 @@ import { Avatar } from "./base/avatar"; import { styled } from "../styled"; import { useThreadConfig } from "./thread-config"; import { AssistantActionBar } from "./assistant-action-bar"; +import { Text } from "./text"; export const AssistantMessage: FC = () => { return ( @@ -24,7 +25,7 @@ export const AssistantMessage: FC = () => { AssistantMessage.displayName = "AssistantMessage"; -const AssistantAvatar: FC = () => { +export const AssistantAvatar: FC = () => { const { assistantAvatar: avatar = { fallback: "A" } } = useThreadConfig(); return ; }; @@ -46,10 +47,12 @@ export const AssistantMessageContent = forwardRef< HTMLDivElement, AssistantMessageContentProps >(({ components: componentsProp, ...rest }, ref) => { - const { assistantMessage: { components } = {} } = useThreadConfig(); + const { assistantMessage: { components = {} } = {} } = useThreadConfig(); return ( - + ); }); diff --git a/packages/react-ui/src/components/index.ts b/packages/react-ui/src/components/index.ts index 376685559..fa72a5e26 100644 --- a/packages/react-ui/src/components/index.ts +++ b/packages/react-ui/src/components/index.ts @@ -6,6 +6,7 @@ export { type UserMessageConfig, type AssistantMessageConfig, type StringsConfig, + type SuggestionConfig, type ThreadConfigProviderProps, } from "./thread-config"; @@ -35,6 +36,7 @@ export { export { AssistantMessage, AssistantMessageRoot, + AssistantAvatar, AssistantMessageContent, type AssistantMessageContentProps, } from "./assistant-message"; @@ -74,7 +76,17 @@ export { export { AssistantModal, AssistantModalTrigger } from "./assistant-modal"; -export { ThreadWelcome, ThreadWelcomeRoot } from "./thread-welcome"; +export { + ThreadWelcome, + ThreadWelcomeRoot, + ThreadWelcomeAvatar, + ThreadWelcomeMessage, + type ThreadWelcomeMessageProps, + ThreadWelcomeSuggestions, + ThreadWelcomeSuggestion, +} from "./thread-welcome"; + +export { Text } from "./text"; export { MarkdownText } from "./markdown-text"; diff --git a/packages/react-ui/src/components/text.tsx b/packages/react-ui/src/components/text.tsx new file mode 100644 index 000000000..f68ddd89b --- /dev/null +++ b/packages/react-ui/src/components/text.tsx @@ -0,0 +1,17 @@ +import { FC } from "react"; +import { + ContentPartPrimitive, + TextContentPartProps, +} from "@assistant-ui/react"; + +export const Text: FC = ({ status }) => { + return ( +

+ +

+ ); +}; diff --git a/packages/react-ui/src/components/thread-config.tsx b/packages/react-ui/src/components/thread-config.tsx index 7acaf000b..b158be525 100644 --- a/packages/react-ui/src/components/thread-config.tsx +++ b/packages/react-ui/src/components/thread-config.tsx @@ -1,9 +1,20 @@ -import { TextContentPartComponent } from "@assistant-ui/react"; +import { + AssistantRuntimeProvider, + TextContentPartComponent, +} from "@assistant-ui/react"; import { FC, PropsWithChildren, createContext, useContext } from "react"; import { AvatarProps } from "./base/avatar"; +import { AssistantRuntime } from "@assistant-ui/react"; + +export type SuggestionConfig = { + icon?: string; + text: string; + prompt?: string; +}; export type ThreadWelcomeConfig = { message?: string | null | undefined; + suggestions?: SuggestionConfig[] | undefined; }; export type UserMessageConfig = { diff --git a/packages/react-ui/src/components/thread-welcome.tsx b/packages/react-ui/src/components/thread-welcome.tsx index 1f945b98a..9dbc7a8a3 100644 --- a/packages/react-ui/src/components/thread-welcome.tsx +++ b/packages/react-ui/src/components/thread-welcome.tsx @@ -3,13 +3,14 @@ import { ThreadPrimitive } from "@assistant-ui/react"; import { ComponentPropsWithoutRef, forwardRef, type FC } from "react"; import { styled } from "../styled"; import { Avatar } from "./base/avatar"; -import { useThreadConfig } from "./thread-config"; +import { SuggestionConfig, useThreadConfig } from "./thread-config"; export const ThreadWelcome: FC = () => { return ( + ); }; @@ -35,7 +36,7 @@ export const ThreadWelcomeRoot = forwardRef< ThreadWelcomeRoot.displayName = "ThreadWelcomeRoot"; -const ThreadWelcomeAvatar: FC = () => { +export const ThreadWelcomeAvatar: FC = () => { const { assistantAvatar: avatar = { fallback: "A" } } = useThreadConfig(); return ; }; @@ -44,16 +45,16 @@ const ThreadWelcomeMessageStyled = styled("p", { className: "aui-thread-welcome-message", }); -type ThreadWelcomeMessageProps = Omit< +export type ThreadWelcomeMessageProps = Omit< ComponentPropsWithoutRef, "children" > & { message?: string | undefined }; -const ThreadWelcomeMessage = forwardRef< +export const ThreadWelcomeMessage = forwardRef< HTMLParagraphElement, ThreadWelcomeMessageProps >(({ message: messageProp, ...rest }, ref) => { - const { welcome: { message } = { message: "How can I help you today?" } } = + const { welcome: { message = "How can I help you today?" } = {} } = useThreadConfig(); return ( @@ -63,3 +64,45 @@ const ThreadWelcomeMessage = forwardRef< }); ThreadWelcomeMessage.displayName = "ThreadWelcomeMessage"; + +const ThreadWelcomeSuggestionContainer = styled("div", { + className: "aui-thread-welcome-suggestion-container", +}); + +const ThreadWelcomeSuggestionStyled = styled(ThreadPrimitive.Suggestion, { + className: "aui-thread-welcome-suggestion", +}); + +export type ThreadWelcomeSuggestionProps = { + suggestion: SuggestionConfig; +}; + +export const ThreadWelcomeSuggestion: FC = ({ + suggestion: { text, prompt }, +}) => { + return ( + + {text} + + ); +}; + +export const ThreadWelcomeSuggestions: FC = () => { + const { welcome: { suggestions } = {} } = useThreadConfig(); + return ( + + {suggestions?.map((suggestion) => ( + + ))} + + ); +}; + +ThreadWelcomeSuggestions.displayName = "ThreadWelcomeSuggestions"; diff --git a/packages/react-ui/src/components/user-message.tsx b/packages/react-ui/src/components/user-message.tsx index acb671ec3..97b709f68 100644 --- a/packages/react-ui/src/components/user-message.tsx +++ b/packages/react-ui/src/components/user-message.tsx @@ -6,6 +6,7 @@ import { BranchPicker } from "./branch-picker"; import { styled } from "../styled"; import { MessagePrimitiveContentProps } from "@assistant-ui/react"; import { UserActionBar } from "./user-action-bar"; +import { Text } from "./text"; export const UserMessage: FC = () => { return ( @@ -38,7 +39,7 @@ export const UserMessageContent = forwardRef< >(({ components, ...props }, ref) => { return ( - + ); }); diff --git a/packages/react-ui/src/styles.css b/packages/react-ui/src/styles.css index f300abed1..4d932231a 100644 --- a/packages/react-ui/src/styles.css +++ b/packages/react-ui/src/styles.css @@ -221,11 +221,12 @@ @apply font-medium; } - /* TODO text content part */ + .aui-text { + @apply whitespace-pre-line; + } - .aui-content-part-in-progress { - @apply bg-foreground inline-block size-3 rounded-full; - @apply animate-aui-pulse; + .aui-text-in-progress::after { + @apply animate-aui-pulse font-sans content-['\25CF'] ltr:ml-1 rtl:mr-1; } .animate-aui-pulse { diff --git a/packages/react/src/primitive-hooks/thread/useThreadSuggestion.tsx b/packages/react/src/primitive-hooks/thread/useThreadSuggestion.tsx index dfeade443..1b503e5be 100644 --- a/packages/react/src/primitive-hooks/thread/useThreadSuggestion.tsx +++ b/packages/react/src/primitive-hooks/thread/useThreadSuggestion.tsx @@ -1,5 +1,6 @@ import { useCallback } from "react"; import { useThreadContext } from "../../context"; +import { useAppendMessage } from "../../hooks"; export type UseApplyThreadSuggestionProps = { prompt: string; @@ -13,16 +14,18 @@ export const useThreadSuggestion = ({ }: UseApplyThreadSuggestionProps) => { const { useThread, useComposer } = useThreadContext(); + const append = useAppendMessage(); const disabled = useThread((t) => t.isRunning); const callback = useCallback(() => { const thread = useThread.getState(); const composer = useComposer.getState(); - composer.setValue(prompt); - if (autoSend && !thread.isRunning) { - composer.send(); + append(prompt); + composer.setValue(""); + } else { + composer.setValue(prompt); } - }, [useThread, useComposer, prompt, autoSend]); + }, [useThread, useComposer, autoSend, append, prompt]); if (disabled) return null; return callback;