Conversation.tsx 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. import { ArrowDownIcon } from 'lucide-react'
  2. import type { ComponentProps } from 'react'
  3. import { useCallback } from 'react'
  4. import { Button, cn } from 'ui'
  5. import { StickToBottom, useStickToBottomContext } from 'use-stick-to-bottom'
  6. type ConversationProps = ComponentProps<typeof StickToBottom>
  7. type ConversationContentProps = ComponentProps<typeof StickToBottom.Content>
  8. type ConversationScrollButtonProps = ComponentProps<typeof Button>
  9. export const Conversation = ({ className, ...props }: ConversationProps) => (
  10. <StickToBottom
  11. className={cn('relative flex-1 overflow-y-auto', className)}
  12. initial="smooth"
  13. resize="smooth"
  14. role="log"
  15. {...props}
  16. />
  17. )
  18. export const ConversationContent = ({ className, ...props }: ConversationContentProps) => (
  19. <StickToBottom.Content className={cn('p-4', className)} {...props} />
  20. )
  21. export const ConversationScrollButton = ({
  22. className,
  23. ...props
  24. }: ConversationScrollButtonProps) => {
  25. const { isAtBottom, scrollToBottom } = useStickToBottomContext()
  26. const handleScrollToBottom = useCallback(() => {
  27. scrollToBottom()
  28. }, [scrollToBottom])
  29. return (
  30. !isAtBottom && (
  31. <Button
  32. className={cn('absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full', className)}
  33. onClick={handleScrollToBottom}
  34. size="tiny"
  35. type="default"
  36. {...props}
  37. >
  38. <ArrowDownIcon className="size-4" />
  39. </Button>
  40. )
  41. )
  42. }