| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- import * as React from 'react';
- import { mergeProps } from '@base-ui/react/merge-props';
- import { useRender } from '@base-ui/react/use-render';
- import { cva, type VariantProps } from 'class-variance-authority';
- import { cn } from '@/lib/utils';
- import { Button } from '@/components/ui/button';
- const attachmentVariants = cva(
- 'rounded-xl w-fit focus-within:ring-1 focus-within:ring-ring/50 group/attachment relative flex max-w-full min-w-0 shrink-0 flex-wrap border bg-card text-card-foreground transition-colors has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed',
- {
- variants: {
- size: {
- default:
- 'gap-2 has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2 text-sm',
- sm: 'gap-2.5 has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5 text-xs',
- xs: 'gap-1.5 has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1 text-xs rounded-lg',
- },
- orientation: {
- horizontal: 'min-w-40 items-center',
- vertical: 'w-24 has-data-[slot=attachment-content]:w-30 flex-col',
- },
- },
- },
- );
- function Attachment({
- className,
- state = 'done',
- size = 'default',
- orientation = 'horizontal',
- ...props
- }: React.ComponentProps<'div'> &
- VariantProps<typeof attachmentVariants> & {
- state?: 'idle' | 'uploading' | 'processing' | 'error' | 'done';
- }) {
- return (
- <div
- data-slot="attachment"
- data-state={state}
- data-size={size}
- data-orientation={orientation}
- className={cn(attachmentVariants({ size, orientation }), className)}
- {...props}
- />
- );
- }
- const attachmentMediaVariants = cva(
- "bg-muted text-foreground w-10 rounded-lg group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md [&_svg:not([class*='size-'])]:size-4 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5 group-data-[orientation=vertical]/attachment:w-full group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! relative flex aspect-square shrink-0 items-center justify-center overflow-hidden group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive [&_svg]:pointer-events-none",
- {
- variants: {
- variant: {
- icon: '',
- image:
- 'opacity-60 group-data-[state=idle]/attachment:opacity-100 group-data-[state=done]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover',
- },
- },
- defaultVariants: {
- variant: 'icon',
- },
- },
- );
- function AttachmentMedia({
- className,
- variant = 'icon',
- ...props
- }: React.ComponentProps<'div'> & VariantProps<typeof attachmentMediaVariants>) {
- return (
- <div
- data-slot="attachment-media"
- data-variant={variant}
- className={cn(attachmentMediaVariants({ variant }), className)}
- {...props}
- />
- );
- }
- function AttachmentContent({
- className,
- ...props
- }: React.ComponentProps<'div'>) {
- return (
- <div
- data-slot="attachment-content"
- className={cn(
- 'leading-tight group-data-[orientation=vertical]/attachment:px-1 max-w-full min-w-0 flex-1',
- className,
- )}
- {...props}
- />
- );
- }
- function AttachmentTitle({
- className,
- ...props
- }: React.ComponentProps<'span'>) {
- return (
- <span
- data-slot="attachment-title"
- className={cn(
- 'font-medium block max-w-full min-w-0 truncate group-data-[state=processing]/attachment:shimmer group-data-[state=uploading]/attachment:shimmer',
- className,
- )}
- {...props}
- />
- );
- }
- function AttachmentDescription({
- className,
- ...props
- }: React.ComponentProps<'span'>) {
- return (
- <span
- data-slot="attachment-description"
- className={cn(
- 'mt-0.5 text-xs block min-w-0 truncate text-muted-foreground group-data-[state=error]/attachment:text-destructive/80',
- 'max-w-full',
- className,
- )}
- {...props}
- />
- );
- }
- function AttachmentActions({
- className,
- ...props
- }: React.ComponentProps<'div'>) {
- return (
- <div
- data-slot="attachment-actions"
- className={cn(
- 'group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 relative z-20 group-data-[orientation=vertical]/attachment:gap-1 flex shrink-0 items-center',
- className,
- )}
- {...props}
- />
- );
- }
- function AttachmentAction({
- className,
- variant,
- size = 'icon-xs',
- ...props
- }: React.ComponentProps<typeof Button>) {
- return (
- <Button
- data-slot="attachment-action"
- variant={variant ?? 'ghost'}
- size={size}
- className={cn(className)}
- {...props}
- />
- );
- }
- function AttachmentTrigger({
- className,
- render,
- type,
- ...props
- }: useRender.ComponentProps<'button'>) {
- return useRender({
- defaultTagName: 'button',
- props: mergeProps<'button'>(
- {
- type: render ? type : (type ?? 'button'),
- className: cn('absolute inset-0 z-10 outline-none', className),
- },
- props,
- ),
- render,
- state: {
- slot: 'attachment-trigger',
- },
- });
- }
- function AttachmentGroup({ className, ...props }: React.ComponentProps<'div'>) {
- return (
- <div
- data-slot="attachment-group"
- className={cn(
- 'gap-3 scroll-px-1 py-1 flex min-w-0 scroll-fade-x snap-x snap-mandatory scrollbar-none overflow-x-auto overscroll-x-contain *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start',
- className,
- )}
- {...props}
- />
- );
- }
- export {
- Attachment,
- AttachmentGroup,
- AttachmentMedia,
- AttachmentContent,
- AttachmentTitle,
- AttachmentDescription,
- AttachmentActions,
- AttachmentAction,
- AttachmentTrigger,
- };
|