message-scroller.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. 'use client';
  2. import * as React from 'react';
  3. import {
  4. MessageScroller as MessageScrollerPrimitive,
  5. useMessageScroller,
  6. useMessageScrollerScrollable,
  7. useMessageScrollerVisibility,
  8. } from '@shadcn/react/message-scroller';
  9. import { cn } from '@/lib/utils';
  10. import { Button } from '@/components/ui/button';
  11. import { ArrowDownIcon } from 'lucide-react';
  12. function MessageScrollerProvider(
  13. props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,
  14. ) {
  15. return <MessageScrollerPrimitive.Provider {...props} />;
  16. }
  17. function MessageScroller({
  18. className,
  19. ...props
  20. }: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {
  21. return (
  22. <MessageScrollerPrimitive.Root
  23. data-slot="message-scroller"
  24. className={cn(
  25. 'group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden',
  26. className,
  27. )}
  28. {...props}
  29. />
  30. );
  31. }
  32. function MessageScrollerViewport({
  33. className,
  34. ...props
  35. }: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {
  36. return (
  37. <MessageScrollerPrimitive.Viewport
  38. data-slot="message-scroller-viewport"
  39. className={cn(
  40. 'size-full min-h-0 min-w-0 scroll-fade-b scrollbar-thin scrollbar-gutter-stable overflow-y-auto overscroll-contain contain-content data-autoscrolling:scrollbar-thumb-transparent data-autoscrolling:scrollbar-track-transparent',
  41. className,
  42. )}
  43. {...props}
  44. />
  45. );
  46. }
  47. function MessageScrollerContent({
  48. className,
  49. ...props
  50. }: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {
  51. return (
  52. <MessageScrollerPrimitive.Content
  53. data-slot="message-scroller-content"
  54. className={cn('gap-6 flex h-max min-h-full flex-col', className)}
  55. {...props}
  56. />
  57. );
  58. }
  59. function MessageScrollerItem({
  60. className,
  61. scrollAnchor = false,
  62. ...props
  63. }: React.ComponentProps<typeof MessageScrollerPrimitive.Item>) {
  64. return (
  65. <MessageScrollerPrimitive.Item
  66. data-slot="message-scroller-item"
  67. scrollAnchor={scrollAnchor}
  68. className={cn(
  69. 'min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]',
  70. className,
  71. )}
  72. {...props}
  73. />
  74. );
  75. }
  76. function MessageScrollerButton({
  77. direction = 'end',
  78. className,
  79. children,
  80. render,
  81. variant = 'secondary',
  82. size = 'icon-sm',
  83. ...props
  84. }: React.ComponentProps<typeof MessageScrollerPrimitive.Button> &
  85. Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>) {
  86. return (
  87. <MessageScrollerPrimitive.Button
  88. data-slot="message-scroller-button"
  89. data-direction={direction}
  90. data-variant={variant}
  91. data-size={size}
  92. direction={direction}
  93. className={cn(
  94. 'absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180',
  95. className,
  96. )}
  97. render={render ?? <Button variant={variant} size={size} />}
  98. {...props}
  99. >
  100. {children ?? (
  101. <>
  102. <ArrowDownIcon />
  103. <span className="sr-only">
  104. {direction === 'end' ? 'Scroll to end' : 'Scroll to start'}
  105. </span>
  106. </>
  107. )}
  108. </MessageScrollerPrimitive.Button>
  109. );
  110. }
  111. export {
  112. MessageScrollerProvider,
  113. MessageScroller,
  114. MessageScrollerViewport,
  115. MessageScrollerContent,
  116. MessageScrollerItem,
  117. MessageScrollerButton,
  118. useMessageScroller,
  119. useMessageScrollerScrollable,
  120. useMessageScrollerVisibility,
  121. };