Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/apollo-wind/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
"@shadcn/react": "0.2.1",
"@tailwindcss/postcss": "^4.1.17",
"@tanstack/react-table": "^8.21.3",
"@uipath/apollo-core": "workspace:*",
Expand Down
191 changes: 191 additions & 0 deletions packages/apollo-wind/src/components/ui/attachment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib';
Comment on lines +1 to +5
Comment on lines +1 to +5

const attachmentVariants = cva(
'group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-1 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed',
{
variants: {
size: {
default:
'gap-2 text-sm has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2',
sm: 'gap-2.5 text-xs has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5',
xs: 'gap-1.5 rounded-lg text-xs has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1',
},
orientation: {
horizontal: 'min-w-40 items-center',
vertical: 'w-24 flex-col has-data-[slot=attachment-content]:w-30',
},
},
}
);

export interface AttachmentProps
extends React.ComponentProps<'div'>,
VariantProps<typeof attachmentVariants> {
state?: 'idle' | 'uploading' | 'processing' | 'error' | 'done';
}

function Attachment({
className,
state = 'done',
size = 'default',
orientation = 'horizontal',
...props
}: AttachmentProps) {
return (
<div
data-slot="attachment"
data-state={state}
data-size={size}
data-orientation={orientation}
className={cn(attachmentVariants({ size, orientation }), className)}
{...props}
/>
);
}

const attachmentMediaVariants = cva(
"relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5",
{
variants: {
variant: {
icon: '',
image:
'opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover',
},
},
defaultVariants: {
variant: 'icon',
},
}
);

export interface AttachmentMediaProps
extends React.ComponentProps<'div'>,
VariantProps<typeof attachmentMediaVariants> {}

function AttachmentMedia({ className, variant = 'icon', ...props }: AttachmentMediaProps) {
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(
'max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1',
className
)}
{...props}
/>
);
}

function AttachmentTitle({ className, ...props }: React.ComponentProps<'span'>) {
return (
<span
data-slot="attachment-title"
className={cn(
'block max-w-full min-w-0 truncate font-medium 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 block max-w-full min-w-0 truncate text-xs text-muted-foreground group-data-[state=error]/attachment:text-destructive/80',
className
)}
{...props}
/>
);
}

function AttachmentActions({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="attachment-actions"
className={cn(
'relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1',
className
)}
{...props}
/>
);
}

function AttachmentAction({
className,
variant,
size,
icon = true,
...props
}: React.ComponentProps<typeof Button>) {
return (
<Button
data-slot="attachment-action"
variant={variant ?? 'ghost'}
size={size ?? '3xs'}
icon={icon}
className={cn(className)}
{...props}
/>
);
}

export interface AttachmentTriggerProps extends React.ComponentProps<'button'> {
asChild?: boolean;
}

function AttachmentTrigger({ className, asChild = false, type, ...props }: AttachmentTriggerProps) {
const Comp = asChild ? Slot : 'button';
return (
<Comp
data-slot="attachment-trigger"
type={asChild ? undefined : (type ?? 'button')}
className={cn('absolute inset-0 z-10 outline-none', className)}
{...props}
/>
);
}

function AttachmentGroup({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="attachment-group"
className={cn(
'flex min-w-0 scroll-fade-x snap-x snap-mandatory scroll-px-1 scrollbar-none gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start',
className
)}
{...props}
/>
);
}

export {
Attachment,
AttachmentGroup,
AttachmentMedia,
AttachmentContent,
AttachmentTitle,
AttachmentDescription,
AttachmentActions,
AttachmentAction,
AttachmentTrigger,
};
Loading
Loading