mirror of
https://github.com/supabase/supabase.git
synced 2026-10-14 05:39:11 +03:00
remove unused stuff
This commit is contained in:
1 parent
9e20c4d6a6
commit
ff5037cf5b
19 files changed
-2149
No files matched your search
@@ -1,48 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import { Slot } from '@radix-ui/react-slot'
|
||||
import { VariantProps, cva } from 'class-variance-authority'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||
outline: 'border border-input hover:bg-accent hover:text-accent-foreground',
|
||||
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'underline-offset-4 hover:underline text-primary',
|
||||
},
|
||||
size: {
|
||||
default: 'h-10 py-2 px-4',
|
||||
sm: 'h-9 px-3 rounded-md',
|
||||
lg: 'h-11 px-8 rounded-md',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : 'button'
|
||||
return (
|
||||
<Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = 'Button'
|
||||
|
||||
export { Button, buttonVariants }
|
||||
@@ -1,57 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react'
|
||||
import { DayPicker } from 'react-day-picker'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
import { buttonVariants } from '@ui/components/shadcn/button'
|
||||
|
||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>
|
||||
|
||||
function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
|
||||
return (
|
||||
<DayPicker
|
||||
showOutsideDays={showOutsideDays}
|
||||
className={cn('p-3', className)}
|
||||
classNames={{
|
||||
months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
|
||||
month: 'space-y-4',
|
||||
caption: 'flex justify-center pt-1 relative items-center',
|
||||
caption_label: 'text-sm font-medium',
|
||||
nav: 'space-x-1 flex items-center',
|
||||
nav_button: cn(
|
||||
buttonVariants({ variant: 'outline' }),
|
||||
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100'
|
||||
),
|
||||
nav_button_previous: 'absolute left-1',
|
||||
nav_button_next: 'absolute right-1',
|
||||
table: 'w-full border-collapse space-y-1',
|
||||
head_row: 'flex',
|
||||
head_cell: 'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
|
||||
row: 'flex w-full mt-2',
|
||||
cell: 'text-center text-sm p-0 relative [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
|
||||
day: cn(
|
||||
buttonVariants({ variant: 'ghost' }),
|
||||
'h-9 w-9 p-0 font-normal aria-selected:opacity-100'
|
||||
),
|
||||
day_selected:
|
||||
'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
|
||||
day_today: 'bg-accent text-accent-foreground',
|
||||
day_outside: 'text-muted-foreground opacity-50',
|
||||
day_disabled: 'text-muted-foreground opacity-50',
|
||||
day_range_middle: 'aria-selected:bg-accent aria-selected:text-accent-foreground',
|
||||
day_hidden: 'invisible',
|
||||
...classNames,
|
||||
}}
|
||||
components={{
|
||||
IconLeft: ({ ...props }) => <ChevronLeft className="h-4 w-4" />,
|
||||
IconRight: ({ ...props }) => <ChevronRight className="h-4 w-4" />,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Calendar.displayName = 'Calendar'
|
||||
|
||||
export { Calendar }
|
||||
@@ -1,145 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import { DialogProps } from '@radix-ui/react-dialog'
|
||||
import { Command as CommandPrimitive } from 'cmdk-supabase'
|
||||
import { Search } from 'lucide-react'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
import { Dialog, DialogContent } from '@ui/components/shadcn/dialog'
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Command.displayName = CommandPrimitive.displayName
|
||||
|
||||
interface CommandDialogProps extends DialogProps {}
|
||||
|
||||
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0 shadow-2xl">
|
||||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'placeholder:text-foreground-muted flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||
>((props, ref) => (
|
||||
<CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />
|
||||
))
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn('-mx-1 h-px bg-border', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
|
||||
const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
CommandShortcut.displayName = 'CommandShortcut'
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
||||
import { X } from 'lucide-react'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
|
||||
const Dialog = DialogPrimitive.Root
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger
|
||||
|
||||
const DialogPortal = ({ className, children, ...props }: DialogPrimitive.DialogPortalProps) => (
|
||||
<DialogPrimitive.Portal className={cn(className)} {...props}>
|
||||
<div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">
|
||||
{children}
|
||||
</div>
|
||||
</DialogPrimitive.Portal>
|
||||
)
|
||||
DialogPortal.displayName = DialogPrimitive.Portal.displayName
|
||||
|
||||
const DialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed z-50 grid w-full gap-4 rounded-b-lg border bg-background p-6 shadow-lg animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
))
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||
|
||||
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)} {...props} />
|
||||
)
|
||||
DialogHeader.displayName = 'DialogHeader'
|
||||
|
||||
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogFooter.displayName = 'DialogFooter'
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn('text-lg font-semibold leading-none tracking-tight', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn('text-sm text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import * as LabelPrimitive from '@radix-ui/react-label'
|
||||
import { Slot } from '@radix-ui/react-slot'
|
||||
import {
|
||||
Controller,
|
||||
ControllerProps,
|
||||
FieldPath,
|
||||
FieldValues,
|
||||
FormProvider,
|
||||
useFormContext,
|
||||
} from 'react-hook-form'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
import { Label } from '@ui/components/shadcn/label'
|
||||
|
||||
import { useId } from '@radix-ui/react-id'
|
||||
|
||||
const Form = FormProvider
|
||||
|
||||
type FormFieldContextValue<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
> = {
|
||||
name: TName
|
||||
}
|
||||
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue)
|
||||
|
||||
const FormField = <
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
>({
|
||||
...props
|
||||
}: ControllerProps<TFieldValues, TName>) => {
|
||||
return (
|
||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||
<Controller {...props} />
|
||||
</FormFieldContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const useFormField = () => {
|
||||
const fieldContext = React.useContext(FormFieldContext)
|
||||
const itemContext = React.useContext(FormItemContext)
|
||||
const { getFieldState, formState } = useFormContext()
|
||||
|
||||
const fieldState = getFieldState(fieldContext.name, formState)
|
||||
|
||||
if (!fieldContext) {
|
||||
throw new Error('useFormField should be used within <FormField>')
|
||||
}
|
||||
|
||||
const { id } = itemContext
|
||||
|
||||
return {
|
||||
id,
|
||||
name: fieldContext.name,
|
||||
formItemId: `${id}-form-item`,
|
||||
formDescriptionId: `${id}-form-item-description`,
|
||||
formMessageId: `${id}-form-item-message`,
|
||||
...fieldState,
|
||||
}
|
||||
}
|
||||
|
||||
type FormItemContextValue = {
|
||||
id: string
|
||||
}
|
||||
|
||||
const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue)
|
||||
|
||||
const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => {
|
||||
// const id = React.useId()
|
||||
const id = useId()
|
||||
console.log('id', id)
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div ref={ref} className={cn('space-y-2', className)} {...props} />
|
||||
</FormItemContext.Provider>
|
||||
)
|
||||
}
|
||||
)
|
||||
FormItem.displayName = 'FormItem'
|
||||
|
||||
const FormLabel = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { error, formItemId } = useFormField()
|
||||
|
||||
return (
|
||||
<Label
|
||||
ref={ref}
|
||||
className={cn(error && 'text-destructive', className)}
|
||||
htmlFor={formItemId}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormLabel.displayName = 'FormLabel'
|
||||
|
||||
const FormControl = React.forwardRef<
|
||||
React.ElementRef<typeof Slot>,
|
||||
React.ComponentPropsWithoutRef<typeof Slot>
|
||||
>(({ ...props }, ref) => {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
||||
|
||||
return (
|
||||
<Slot
|
||||
ref={ref}
|
||||
id={formItemId}
|
||||
aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
|
||||
aria-invalid={!!error}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormControl.displayName = 'FormControl'
|
||||
|
||||
const FormDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { formDescriptionId } = useFormField()
|
||||
|
||||
return (
|
||||
<p
|
||||
ref={ref}
|
||||
id={formDescriptionId}
|
||||
className={cn('text-sm text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormDescription.displayName = 'FormDescription'
|
||||
|
||||
const FormMessage = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { error, formMessageId } = useFormField()
|
||||
const body = error ? String(error?.message) : children
|
||||
|
||||
if (!body) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<p
|
||||
ref={ref}
|
||||
id={formMessageId}
|
||||
className={cn('text-sm font-medium text-red-900', className)}
|
||||
{...props}
|
||||
>
|
||||
{body}
|
||||
</p>
|
||||
)
|
||||
})
|
||||
FormMessage.displayName = 'FormMessage'
|
||||
|
||||
export {
|
||||
useFormField,
|
||||
Form,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormMessage,
|
||||
FormField,
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
'flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Input.displayName = 'Input'
|
||||
|
||||
export { Input }
|
||||
@@ -1,19 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import * as LabelPrimitive from '@radix-ui/react-label'
|
||||
import { VariantProps, cva } from 'class-variance-authority'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
|
||||
const labelVariants = cva(
|
||||
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
|
||||
)
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
|
||||
))
|
||||
Label.displayName = LabelPrimitive.Root.displayName
|
||||
|
||||
export { Label }
|
||||
@@ -1,29 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import * as PopoverPrimitive from '@radix-ui/react-popover'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
|
||||
const Popover = PopoverPrimitive.Root
|
||||
|
||||
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||
|
||||
const PopoverContent = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
))
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent }
|
||||
@@ -1,118 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import * as SelectPrimitive from '@radix-ui/react-select'
|
||||
import { Check, ChevronDown } from 'lucide-react'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
|
||||
const Select = SelectPrimitive.Root
|
||||
|
||||
const SelectGroup = SelectPrimitive.Group
|
||||
|
||||
const SelectValue = SelectPrimitive.Value
|
||||
|
||||
const SelectTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
))
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
||||
|
||||
const SelectContent = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
>(({ className, children, position = 'popper', ...props }, ref) => (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-80',
|
||||
position === 'popper' && 'translate-y-1',
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
'p-1',
|
||||
position === 'popper' &&
|
||||
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
))
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
||||
|
||||
const SelectLabel = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
||||
|
||||
const SelectItem = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
))
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
||||
|
||||
const SelectSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import * as ToastPrimitives from '@radix-ui/react-toast'
|
||||
import { VariantProps, cva } from 'class-variance-authority'
|
||||
import { X } from 'lucide-react'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
|
||||
const ToastProvider = ToastPrimitives.Provider
|
||||
|
||||
const ToastViewport = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Viewport>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Viewport
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
|
||||
|
||||
const toastVariants = cva(
|
||||
'data-[swipe=move]:transition-none group relative pointer-events-auto flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full data-[state=closed]:slide-out-to-right-full',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-background border',
|
||||
destructive:
|
||||
'group destructive border-destructive bg-destructive text-destructive-foreground',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const Toast = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & VariantProps<typeof toastVariants>
|
||||
>(({ className, variant, ...props }, ref) => {
|
||||
return (
|
||||
<ToastPrimitives.Root
|
||||
ref={ref}
|
||||
className={cn(toastVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
Toast.displayName = ToastPrimitives.Root.displayName
|
||||
|
||||
const ToastAction = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Action>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Action
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-destructive/30 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastAction.displayName = ToastPrimitives.Action.displayName
|
||||
|
||||
const ToastClose = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Close>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Close
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600',
|
||||
className
|
||||
)}
|
||||
toast-close=""
|
||||
{...props}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</ToastPrimitives.Close>
|
||||
))
|
||||
ToastClose.displayName = ToastPrimitives.Close.displayName
|
||||
|
||||
const ToastTitle = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Title ref={ref} className={cn('text-sm font-semibold', className)} {...props} />
|
||||
))
|
||||
ToastTitle.displayName = ToastPrimitives.Title.displayName
|
||||
|
||||
const ToastDescription = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Description
|
||||
ref={ref}
|
||||
className={cn('text-sm opacity-90', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastDescription.displayName = ToastPrimitives.Description.displayName
|
||||
|
||||
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
|
||||
|
||||
type ToastActionElement = React.ReactElement<typeof ToastAction>
|
||||
|
||||
export {
|
||||
type ToastProps,
|
||||
type ToastActionElement,
|
||||
ToastProvider,
|
||||
ToastViewport,
|
||||
Toast,
|
||||
ToastTitle,
|
||||
ToastDescription,
|
||||
ToastClose,
|
||||
ToastAction,
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// Button.stories.ts|tsx
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import { Accordion, AccordionItem } from './Accordion'
|
||||
import { Badge } from '../../../Badge'
|
||||
|
||||
const meta: Meta<typeof Accordion> = {
|
||||
/* 👇 The title prop is optional.
|
||||
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
|
||||
* to learn how to generate automatic titles
|
||||
*/
|
||||
title: 'General/Accordion',
|
||||
component: Accordion,
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof Accordion>
|
||||
|
||||
/*
|
||||
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
|
||||
* See https://storybook.js.org/docs/react/api/csf
|
||||
* to learn how to use render functions.
|
||||
*/
|
||||
|
||||
export const Default = {
|
||||
args: {
|
||||
type: 'default',
|
||||
},
|
||||
render: ({ children, type }: any) => (
|
||||
<Accordion type={type} openBehaviour="single" collapsible className="w-full">
|
||||
<Accordion.Item value="item-1">
|
||||
<Accordion.Trigger>
|
||||
<span className="text-scale-900 group-hover:text-scale-1200">Title of the thing</span>
|
||||
</Accordion.Trigger>
|
||||
<Accordion.Content>Yes. It adheres to the WAI-ARIA design pattern.</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="item-2">
|
||||
<Accordion.Trigger>Is it styled?</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
Yes. It comes with default styles that matches the other components' aesthetic.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="item-3">
|
||||
<Accordion.Trigger>Is it animated?</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
Yes. It's animated by default, but you can disable it if you prefer.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
),
|
||||
}
|
||||
|
||||
export const Bordered = {
|
||||
args: {
|
||||
type: 'bordered',
|
||||
},
|
||||
render: ({ children, type }: any) => (
|
||||
<Accordion type={type} openBehaviour="single" collapsible className="w-full">
|
||||
<Accordion.Item value="item-1">
|
||||
<Accordion.Trigger>Is it accessible?</Accordion.Trigger>
|
||||
<Accordion.Content>Yes. It adheres to the WAI-ARIA design pattern.</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="item-2">
|
||||
<Accordion.Trigger>Is it styled?</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
Yes. It comes with default styles that matches the other components' aesthetic.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="item-3">
|
||||
<Accordion.Trigger>Is it animated?</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
Yes. It's animated by default, but you can disable it if you prefer.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
),
|
||||
}
|
||||
@@ -1,235 +0,0 @@
|
||||
import * as AccordionPrimitive from '@radix-ui/react-accordion'
|
||||
import { cn } from './../../lib/utils'
|
||||
|
||||
import { VariantProps, cva, cx } from 'class-variance-authority'
|
||||
import { ChevronDown } from 'lucide-react'
|
||||
import React, { createContext, useContext, useState } from 'react'
|
||||
|
||||
export type AccordionRootVariantsProps = VariantProps<typeof accordionRootVariants>
|
||||
const accordionRootVariants = cva('flex flex-col', {
|
||||
variants: {
|
||||
type: {
|
||||
default: 'space-y-3',
|
||||
bordered: '-space-y-px',
|
||||
},
|
||||
defaultVariants: {
|
||||
type: 'default',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export type AccordionItemVariantsProps = VariantProps<typeof accordionItemVariants>
|
||||
const accordionItemVariants = cva(
|
||||
'group first:rounded-tl-md first:rounded-tr-md last:rounded-bl-md last:rounded-br-md',
|
||||
{
|
||||
variants: {
|
||||
type: {
|
||||
default: 'overflow-hidden',
|
||||
bordered: 'border border-scale-700',
|
||||
},
|
||||
justified: {
|
||||
true: 'justify-between',
|
||||
false: '',
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const accordionTriggerVariants = cva(
|
||||
`flex flex-row items-center w-full text-left cursor-pointer focus-visible:ring-1 focus-visible:z-10 ring-scale-1100
|
||||
justify-between transition-all hover:underline [&[data-state=open]>svg]:rotate-180`,
|
||||
{
|
||||
variants: {
|
||||
type: {
|
||||
default: 'gap-3',
|
||||
bordered: `
|
||||
px-6 py-4
|
||||
font-medium text-base bg-transparent
|
||||
transition-colors hover:bg-scale-200
|
||||
overflow-hidden
|
||||
group-first:rounded-tl-md group-first:rounded-tr-md
|
||||
group-last:rounded-bl-md group-last:rounded-br-md`,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const accordionContentVariants = cva('pb-4 pt-0', {
|
||||
variants: {
|
||||
type: {
|
||||
default: '',
|
||||
bordered: 'px-6',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
type Type = AccordionRootVariantsProps['type']
|
||||
type Align = 'left' | 'right' | undefined
|
||||
|
||||
interface ContextValue {
|
||||
chevronAlign: Align
|
||||
justified: boolean
|
||||
type: Type
|
||||
defaultValue: AccordionPrimitive.AccordionImplSingleProps['defaultValue']
|
||||
}
|
||||
|
||||
interface AdditionalProps {
|
||||
openBehaviour: 'single' | 'multiple'
|
||||
variant?: Type
|
||||
// Add other additional props here
|
||||
onChange?: (item: string | string[]) => void
|
||||
type?: Type
|
||||
justified?: AccordionItemVariantsProps['justified']
|
||||
chevronAlign?: Align
|
||||
}
|
||||
|
||||
interface AccordionComponent
|
||||
extends React.ForwardRefExoticComponent<
|
||||
ExtendedAccordionProps & React.RefAttributes<HTMLDivElement>
|
||||
> {
|
||||
Item: typeof AccordionItem
|
||||
Content: typeof AccordionContent
|
||||
Trigger: typeof AccordionTrigger
|
||||
}
|
||||
|
||||
export interface AccordionSingleProps extends AccordionPrimitive.AccordionImplSingleProps {
|
||||
openBehaviour: 'single'
|
||||
value?: string
|
||||
// Add other props specific to single accordion
|
||||
}
|
||||
|
||||
export interface AccordionMultipleProps extends AccordionPrimitive.AccordionImplMultipleProps {
|
||||
openBehaviour: 'multiple'
|
||||
value?: string[]
|
||||
// Add other props specific to multiple accordion
|
||||
}
|
||||
|
||||
type ExtendedAccordionProps = (AccordionSingleProps | AccordionMultipleProps) & AdditionalProps
|
||||
|
||||
const AccordionContext = createContext<ContextValue>({
|
||||
chevronAlign: 'left',
|
||||
justified: false, // Set the default value to false
|
||||
type: undefined,
|
||||
defaultValue: undefined,
|
||||
})
|
||||
|
||||
const Accordion: AccordionComponent = React.forwardRef(
|
||||
({ openBehaviour, type, chevronAlign, justified, defaultValue, ...props }, ref) => {
|
||||
function handleOnChange(e: string | string[]) {
|
||||
if (props.onChange) props.onChange(e)
|
||||
}
|
||||
|
||||
const contextValue = {
|
||||
chevronAlign,
|
||||
justified: justified || false, // Provide a default value of false
|
||||
type: type || 'default', // Provide a default value for the type
|
||||
defaultValue: Array.isArray(defaultValue) ? defaultValue.join('') : defaultValue, // Convert array to string
|
||||
}
|
||||
|
||||
if (openBehaviour === 'single') {
|
||||
const { value, children, className, ...singleProps } = props as AccordionSingleProps
|
||||
return (
|
||||
<AccordionPrimitive.Root
|
||||
ref={ref}
|
||||
type="single"
|
||||
onValueChange={handleOnChange}
|
||||
value={value}
|
||||
defaultValue={defaultValue}
|
||||
className={cn(accordionRootVariants({ type }), className)}
|
||||
children={
|
||||
<AccordionContext.Provider value={{ ...contextValue }}>
|
||||
{children}
|
||||
</AccordionContext.Provider>
|
||||
}
|
||||
{...singleProps}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
const { value, children, className, ...multipleProps } = props as AccordionMultipleProps
|
||||
return (
|
||||
<AccordionPrimitive.Root
|
||||
ref={ref}
|
||||
type="multiple"
|
||||
onValueChange={handleOnChange}
|
||||
value={value}
|
||||
className={cn(accordionRootVariants({ type }), className)}
|
||||
children={
|
||||
<AccordionContext.Provider value={{ ...contextValue }}>
|
||||
<div>{props.children}</div>
|
||||
</AccordionContext.Provider>
|
||||
}
|
||||
{...multipleProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
) as AccordionComponent
|
||||
|
||||
export interface ItemAdditionalProps
|
||||
extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> {}
|
||||
|
||||
export const AccordionItem = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
let { type, justified } = useContext(AccordionContext)
|
||||
|
||||
return (
|
||||
<AccordionPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(accordionItemVariants({ type, justified }), className)}
|
||||
onClick={() => {
|
||||
setOpen(!open)
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
AccordionItem.displayName = AccordionPrimitive.Item.displayName
|
||||
|
||||
export const AccordionTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { type } = useContext(AccordionContext)
|
||||
return (
|
||||
<AccordionPrimitive.Header className="flex">
|
||||
<AccordionPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(accordionTriggerVariants({ type }), className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronDown className="h-4 w-4 transition-transform duration-200" />
|
||||
</AccordionPrimitive.Trigger>
|
||||
</AccordionPrimitive.Header>
|
||||
)
|
||||
})
|
||||
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
|
||||
|
||||
export const AccordionContent = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { type } = useContext(AccordionContext)
|
||||
return (
|
||||
<AccordionPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div className={cx(accordionContentVariants({ type }))}>{children}</div>
|
||||
</AccordionPrimitive.Content>
|
||||
)
|
||||
})
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName
|
||||
|
||||
Accordion.Item = AccordionItem
|
||||
Accordion.Content = AccordionContent
|
||||
Accordion.Trigger = AccordionTrigger
|
||||
export { Accordion }
|
||||
@@ -1,92 +0,0 @@
|
||||
// Button.stories.ts|tsx
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import { Alert, AlertProps } from './Alert'
|
||||
|
||||
import { IconAirplay } from '../Icon/icons/IconAirplay'
|
||||
import { Terminal } from 'lucide-react'
|
||||
|
||||
const meta: Meta<typeof Alert> = {
|
||||
/* 👇 The title prop is optional.
|
||||
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
|
||||
* to learn how to generate automatic titles
|
||||
*/
|
||||
title: 'General/Alert',
|
||||
component: Alert,
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof Alert>
|
||||
|
||||
/*
|
||||
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
|
||||
* See https://storybook.js.org/docs/react/api/csf
|
||||
* to learn how to use render functions.
|
||||
*/
|
||||
|
||||
export const Info = {
|
||||
args: {
|
||||
variant: 'info',
|
||||
withIcon: true,
|
||||
},
|
||||
render: ({ withIcon, variant }: AlertProps) => (
|
||||
<Alert variant={variant} withIcon={withIcon}>
|
||||
<Alert.Title>Info Alert</Alert.Title>
|
||||
<Alert.Description>This is an informative message for your application.</Alert.Description>
|
||||
</Alert>
|
||||
),
|
||||
}
|
||||
|
||||
export const Danger = {
|
||||
args: {
|
||||
variant: 'danger',
|
||||
withIcon: true,
|
||||
},
|
||||
render: ({ withIcon, variant }: AlertProps) => (
|
||||
<Alert variant={variant} withIcon={withIcon}>
|
||||
<Alert.Title>Danger Alert</Alert.Title>
|
||||
<Alert.Description>This is a dangerous warning for your application.</Alert.Description>
|
||||
</Alert>
|
||||
),
|
||||
}
|
||||
|
||||
export const Warning = {
|
||||
args: {
|
||||
variant: 'warning',
|
||||
withIcon: true,
|
||||
},
|
||||
render: ({ withIcon, variant }: AlertProps) => (
|
||||
<Alert variant={variant} withIcon={withIcon}>
|
||||
<Alert.Title>Warning Alert</Alert.Title>
|
||||
<Alert.Description>This is a warning message for your application.</Alert.Description>
|
||||
</Alert>
|
||||
),
|
||||
}
|
||||
|
||||
export const Success = {
|
||||
args: {
|
||||
variant: 'success',
|
||||
withIcon: true,
|
||||
},
|
||||
render: ({ withIcon, variant }: AlertProps) => (
|
||||
<Alert variant={variant} withIcon={withIcon}>
|
||||
<Alert.Title>Success Alert</Alert.Title>
|
||||
<Alert.Description>This is a successful notification for your application.</Alert.Description>
|
||||
</Alert>
|
||||
),
|
||||
}
|
||||
|
||||
export const Neutral = {
|
||||
args: {
|
||||
variant: 'neutral',
|
||||
withIcon: true,
|
||||
},
|
||||
render: ({ withIcon, variant }: AlertProps) => (
|
||||
<Alert variant={variant} withIcon={withIcon}>
|
||||
<Alert.Title>Neutral Alert</Alert.Title>
|
||||
<Alert.Description>This is a neutral message for your application.</Alert.Description>
|
||||
</Alert>
|
||||
),
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
import { cn } from '../../../../lib/utils'
|
||||
import { VariantProps, cva } from 'class-variance-authority'
|
||||
import { AlertOctagon, AlertTriangle, Check, Info } from 'lucide-react'
|
||||
import * as React from 'react'
|
||||
|
||||
export type AlertRootVariantsProps = VariantProps<typeof alertRootVariants>
|
||||
const alertRootVariants = cva(
|
||||
`relative w-full
|
||||
rounded-lg border
|
||||
py-4 px-6
|
||||
[&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11`,
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
danger: `bg-red-200 dark:bg-red-100 text-red-1200 border-red-700 [&>svg]:text-red-1200`,
|
||||
warning: `bg-amber-200 dark:bg-amber-100 border-amber-700 [&>svg]:text-amber-1200`,
|
||||
info: `bg-scale-400 border-scale-500 dark:bg-scale-100 dark:border-scale-300 [&>svg]:text-scale-1200`,
|
||||
success: `bg-brand-300 dark:bg-brand-100 border-brand-700 [&>svg]:text-brand-900`,
|
||||
neutral: `bg-scale-300 dark:bg-scale-300 border-scale-500 [&>svg]:text-scale-900`,
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'info',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const alertTitleVariants = cva('mb-1 font-medium leading-none tracking-tight', {
|
||||
variants: {
|
||||
variant: {
|
||||
danger: `text-red-1200`,
|
||||
warning: `text-amber-1200`,
|
||||
info: `text-scale-1200`,
|
||||
success: `text-brand-1200`,
|
||||
neutral: `text-scale-1200`,
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'info',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const alertDescriptionVariants = cva('text-sm [&_p]:leading-relaxed', {
|
||||
variants: {
|
||||
variant: {
|
||||
danger: 'text-red-1100',
|
||||
warning: 'text-amber-1100',
|
||||
info: 'text-scale-1100',
|
||||
success: 'text-brand-1100',
|
||||
neutral: 'text-scale-1100',
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'info',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
interface ContextValue {
|
||||
variant: AlertRootVariantsProps['variant']
|
||||
}
|
||||
|
||||
const AlertContext = React.createContext<ContextValue>({
|
||||
variant: undefined,
|
||||
})
|
||||
|
||||
// Define the Alert component
|
||||
interface AlertProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof alertRootVariants> {
|
||||
withIcon: boolean
|
||||
}
|
||||
|
||||
interface AlertComponent
|
||||
extends React.ForwardRefExoticComponent<AlertProps & React.RefAttributes<HTMLDivElement>> {
|
||||
Title: typeof AlertTitle
|
||||
Description: typeof AlertDescription
|
||||
}
|
||||
|
||||
type AlertIconVariant = Exclude<AlertRootVariantsProps['variant'], null | undefined>
|
||||
const icons: Record<AlertIconVariant, React.ReactElement> = {
|
||||
danger: <AlertOctagon strokeWidth={1.5} size={18} />,
|
||||
success: <Check strokeWidth={1.5} size={18} />,
|
||||
warning: <AlertTriangle strokeWidth={1.5} size={18} />,
|
||||
info: <Info strokeWidth={1.5} size={18} />,
|
||||
neutral: <></>,
|
||||
}
|
||||
|
||||
const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
|
||||
({ className, withIcon, variant = 'info', children, ...props }, ref) => {
|
||||
const contextValue = {
|
||||
variant,
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
role="alert"
|
||||
className={cn(alertRootVariants({ variant }), className)}
|
||||
{...props}
|
||||
children={
|
||||
<AlertContext.Provider value={{ ...contextValue }}>
|
||||
{withIcon && icons[variant as AlertIconVariant]}
|
||||
{children}
|
||||
</AlertContext.Provider>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
) as AlertComponent
|
||||
|
||||
Alert.displayName = 'Alert'
|
||||
|
||||
// Define the AlertTitle component as a subcomponent of Alert
|
||||
interface AlertTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {}
|
||||
|
||||
const AlertTitle = React.forwardRef<HTMLHeadingElement, AlertTitleProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
const { variant } = React.useContext(AlertContext)
|
||||
console.log('variant', variant)
|
||||
return <h5 ref={ref} className={cn(alertTitleVariants({ variant }), className)} {...props} />
|
||||
}
|
||||
)
|
||||
|
||||
AlertTitle.displayName = 'AlertTitle'
|
||||
|
||||
// Define the AlertDescription component as a subcomponent of Alert
|
||||
interface AlertDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {}
|
||||
|
||||
const AlertDescription = React.forwardRef<HTMLParagraphElement, AlertDescriptionProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
const { variant } = React.useContext(AlertContext)
|
||||
return (
|
||||
<div ref={ref} className={cn(alertDescriptionVariants({ variant }), className)} {...props} />
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
AlertDescription.displayName = 'AlertDescription'
|
||||
|
||||
// Attach the subcomponents to the Alert component
|
||||
Alert.Title = AlertTitle
|
||||
Alert.Description = AlertDescription
|
||||
|
||||
// Export the Alert component
|
||||
export { Alert }
|
||||
@@ -1,155 +0,0 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import { Badge, BadgeProps } from './Badge'
|
||||
|
||||
const meta: Meta<typeof Badge> = {
|
||||
/* 👇 The title prop is optional.
|
||||
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
|
||||
* to learn how to generate automatic titles
|
||||
*/
|
||||
title: 'General/Badge',
|
||||
component: Badge,
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof Badge>
|
||||
|
||||
export const Outline = {
|
||||
args: {
|
||||
variant: 'outline',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Brand = {
|
||||
args: {
|
||||
variant: 'brand',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Scale = {
|
||||
args: {
|
||||
variant: 'scale',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Tomato = {
|
||||
args: {
|
||||
variant: 'tomato',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Red = {
|
||||
args: {
|
||||
variant: 'red',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Crimson = {
|
||||
args: {
|
||||
variant: 'crimson',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Pink = {
|
||||
args: {
|
||||
variant: 'pink',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Purple = {
|
||||
args: {
|
||||
variant: 'purple',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Violet = {
|
||||
args: {
|
||||
variant: 'violet',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Indigo = {
|
||||
args: {
|
||||
variant: 'indigo',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Blue = {
|
||||
args: {
|
||||
variant: 'blue',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Green = {
|
||||
args: {
|
||||
variant: 'green',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Grass = {
|
||||
args: {
|
||||
variant: 'grass',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Orange = {
|
||||
args: {
|
||||
variant: 'orange',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Yellow = {
|
||||
args: {
|
||||
variant: 'yellow',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Amber = {
|
||||
args: {
|
||||
variant: 'amber',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Gold = {
|
||||
args: {
|
||||
variant: 'gold',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Gray = {
|
||||
args: {
|
||||
variant: 'gray',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Slate = {
|
||||
args: {
|
||||
variant: 'slate',
|
||||
},
|
||||
render: ({ variant }: BadgeProps) => <Badge variant={variant}>Hello World</Badge>,
|
||||
}
|
||||
|
||||
export const Large = {
|
||||
args: {
|
||||
size: 'large',
|
||||
},
|
||||
render: ({ size }: BadgeProps) => <Badge size={size}>Hello World</Badge>,
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import { VariantProps, cva } from 'class-variance-authority'
|
||||
|
||||
import { cn } from './../../lib/utils'
|
||||
|
||||
const badgeVariants = cva(
|
||||
'inline-flex items-center border rounded-full px-2.5 py-0.5 text-xs font-normal transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
outline: 'text-foreground',
|
||||
brand: 'bg-brand-200 text-brand-1100 border border-brand-700',
|
||||
scale: 'bg-scale-200 text-scale-1100 border border-scale-700',
|
||||
tomato: `bg-tomato-200 text-tomato-1100 border border-tomato-700`,
|
||||
red: `bg-red-200 text-red-1100 border border-red-700`,
|
||||
crimson: `bg-crimson-200 text-crimson-1100 border border-crimson-700`,
|
||||
pink: `bg-pink-200 text-pink-1100 border border-pink-700`,
|
||||
purple: `bg-purple-200 text-purple-1100 border border-purple-700`,
|
||||
violet: `bg-violet-200 text-violet-1100 border border-violet-700`,
|
||||
indigo: `bg-indigo-200 text-indigo-1100 border border-indigo-700`,
|
||||
blue: `bg-blue-200 text-blue-1100 border border-blue-700`,
|
||||
green: `bg-green-200 text-green-1100 border border-green-700`,
|
||||
grass: `bg-grass-200 text-grass-1100 border border-grass-700`,
|
||||
orange: `bg-orange-200 text-orange-1100 border border-orange-700`,
|
||||
yellow: `bg-yellow-200 text-yellow-1100 border border-yellow-700`,
|
||||
amber: `bg-amber-200 text-amber-1100 border border-amber-700`,
|
||||
gold: `bg-gold-200 text-gold-1100 border border-gold-700`,
|
||||
gray: `bg-gray-200 text-gray-1100 border border-gray-700`,
|
||||
slate: `bg-slate-200 text-slate-1100 border border-slate-700`,
|
||||
},
|
||||
size: {
|
||||
large: 'px-3 py-0.5 rounded-full text-sm',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'scale',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {}
|
||||
|
||||
const Badge = ({ className, variant, size, ...props }: BadgeProps) => {
|
||||
return <div className={cn(badgeVariants({ variant, size }), className)} {...props} />
|
||||
}
|
||||
|
||||
// Badge.displayName = 'Badge'
|
||||
|
||||
export { Badge }
|
||||
@@ -1,175 +0,0 @@
|
||||
// Button.stories.ts|tsx
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import { Button, ButtonProps } from './Button'
|
||||
|
||||
import { IconAirplay } from '../Icon/icons/IconAirplay'
|
||||
|
||||
const meta: Meta<typeof Button> = {
|
||||
/* 👇 The title prop is optional.
|
||||
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
|
||||
* to learn how to generate automatic titles
|
||||
*/
|
||||
title: 'General/Button',
|
||||
component: Button,
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof Button>
|
||||
|
||||
/*
|
||||
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
|
||||
* See https://storybook.js.org/docs/react/api/csf
|
||||
* to learn how to use render functions.
|
||||
*/
|
||||
|
||||
export const Primary = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'primary',
|
||||
},
|
||||
render: ({ children, type }: ButtonProps) => <Button type={type}>{children}</Button>,
|
||||
}
|
||||
export const Default = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'default',
|
||||
},
|
||||
render: ({ children, type }: ButtonProps) => <Button type={type}>{children}</Button>,
|
||||
}
|
||||
|
||||
export const Alternative = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'alternative',
|
||||
},
|
||||
render: ({ children, type }: ButtonProps) => <Button type={type}>{children}</Button>,
|
||||
}
|
||||
|
||||
export const Outline = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'outline',
|
||||
},
|
||||
render: ({ children, type }: ButtonProps) => <Button type={type}>{children}</Button>,
|
||||
}
|
||||
|
||||
export const Secondary = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'secondary',
|
||||
},
|
||||
render: ({ children, type }: ButtonProps) => <Button type={type}>{children}</Button>,
|
||||
}
|
||||
|
||||
export const Dashed = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'dashed',
|
||||
},
|
||||
render: ({ children, type }: ButtonProps) => <Button type={type}>{children}</Button>,
|
||||
}
|
||||
|
||||
export const Link = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'link',
|
||||
},
|
||||
render: ({ children, type }: ButtonProps) => <Button type={type}>{children}</Button>,
|
||||
}
|
||||
|
||||
export const Text = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'text',
|
||||
},
|
||||
render: ({ children, type }: ButtonProps) => <Button type={type}>{children}</Button>,
|
||||
}
|
||||
|
||||
export const Danger = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'danger',
|
||||
},
|
||||
render: ({ children, type }: ButtonProps) => <Button type={type}>{children}</Button>,
|
||||
}
|
||||
|
||||
export const Block = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'primary',
|
||||
block: true,
|
||||
},
|
||||
render: ({ children, type, block }: ButtonProps) => (
|
||||
<Button block type={type}>
|
||||
{children}
|
||||
</Button>
|
||||
),
|
||||
}
|
||||
|
||||
export const Disabled = {
|
||||
args: {
|
||||
children: 'Hello world',
|
||||
type: 'primary',
|
||||
disabled: true,
|
||||
},
|
||||
render: ({ children, type, disabled }: ButtonProps) => (
|
||||
<Button disabled type={type}>
|
||||
{children}
|
||||
</Button>
|
||||
),
|
||||
}
|
||||
|
||||
export const Sizes = {
|
||||
args: {
|
||||
children: 'Change the size below',
|
||||
type: 'primary',
|
||||
size: 'large',
|
||||
},
|
||||
render: ({ children, type, size }: ButtonProps) => (
|
||||
<Button size={size} type={type}>
|
||||
{children}
|
||||
</Button>
|
||||
),
|
||||
}
|
||||
|
||||
export const LeftIcon = {
|
||||
args: {
|
||||
children: 'Change the size below',
|
||||
type: 'primary',
|
||||
iconLeft: <IconAirplay />,
|
||||
},
|
||||
render: ({ children, type, iconLeft }: ButtonProps) => (
|
||||
<Button iconLeft={iconLeft} type={type}>
|
||||
{children}
|
||||
</Button>
|
||||
),
|
||||
}
|
||||
|
||||
export const RightIcon = {
|
||||
args: {
|
||||
children: 'Change the size below',
|
||||
type: 'primary',
|
||||
iconRight: <IconAirplay />,
|
||||
},
|
||||
render: ({ children, type, iconRight }: ButtonProps) => (
|
||||
<Button iconRight={iconRight} type={type}>
|
||||
{children}
|
||||
</Button>
|
||||
),
|
||||
}
|
||||
|
||||
export const Loading = {
|
||||
args: {
|
||||
children: 'Change the size below',
|
||||
type: 'primary',
|
||||
loading: true,
|
||||
},
|
||||
render: ({ children, type, loading }: ButtonProps) => (
|
||||
<Button loading={loading} type={type}>
|
||||
{children}
|
||||
</Button>
|
||||
),
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import { Slot } from '@radix-ui/react-slot'
|
||||
import { VariantProps, cva } from 'class-variance-authority'
|
||||
|
||||
import { IconContext } from '@ui/components/Icon/IconContext'
|
||||
import { IconLoader } from '@ui/components/Icon/icons/IconLoader'
|
||||
|
||||
import { cn } from '@ui/lib/utils'
|
||||
import { sizes } from '@ui/lib/commonCva'
|
||||
|
||||
export type ButtonVariantProps = VariantProps<typeof buttonVariants>
|
||||
const buttonVariants = cva(
|
||||
`relative
|
||||
cursor-pointer
|
||||
inline-flex
|
||||
items-center
|
||||
space-x-2
|
||||
text-center
|
||||
font-regular
|
||||
ease-out
|
||||
duration-200
|
||||
rounded
|
||||
outline-none
|
||||
transition-all
|
||||
outline-0
|
||||
focus-visible:outline-4
|
||||
focus-visible:outline-offset-1`,
|
||||
{
|
||||
variants: {
|
||||
type: {
|
||||
primary: `
|
||||
bg-brand-fixed-1100 hover:bg-brand-fixed-1000
|
||||
text-white
|
||||
bordershadow-brand-fixed-1000 hover:bordershadow-brand-fixed-900 dark:bordershadow-brand-fixed-1000 dark:hover:bordershadow-brand-fixed-1000
|
||||
focus-visible:outline-brand-600
|
||||
shadow-sm`,
|
||||
secondary: `
|
||||
bg-scale-1200
|
||||
text-scale-100 hover:text-scale-800
|
||||
focus-visible:text-scale-600
|
||||
bordershadow-scale-1100 hover:bordershadow-scale-900
|
||||
focus-visible:outline-scale-700
|
||||
shadow-sm`,
|
||||
default: `
|
||||
text-scale-1200
|
||||
bg-scale-100 hover:bg-scale-300
|
||||
bordershadow-scale-600 hover:bordershadow-scale-700
|
||||
dark:bordershadow-scale-700 hover:dark:bordershadow-scale-800
|
||||
dark:bg-scale-500 dark:hover:bg-scale-600
|
||||
focus-visible:outline-brand-600
|
||||
shadow-sm`,
|
||||
alternative: `
|
||||
text-brand-1100
|
||||
bg-brand-200 hover:bg-brand-400
|
||||
bordershadow-brand-600 hover:bordershadow-brand-800
|
||||
dark:bordershadow-brand-700 hover:dark:bordershadow-brand-800
|
||||
focus-visible:border-brand-800
|
||||
focus-visible:outline-brand-600
|
||||
shadow-sm`,
|
||||
outline: `
|
||||
text-scale-1200
|
||||
bg-transparent
|
||||
bordershadow-scale-600 hover:bordershadow-scale-700
|
||||
dark:bordershadow-scale-800 hover:dark:bordershadow-scale-900
|
||||
focus-visible:outline-scale-700`,
|
||||
dashed: `
|
||||
text-scale-1200
|
||||
border
|
||||
border-dashed
|
||||
border-scale-700 hover:border-scale-900
|
||||
bg-transparent
|
||||
focus-visible:outline-scale-700
|
||||
shadow-sm`,
|
||||
link: `
|
||||
text-brand-1100
|
||||
border
|
||||
border-transparent
|
||||
hover:bg-brand-400
|
||||
border-opacity-0
|
||||
bg-opacity-0 dark:bg-opacity-0
|
||||
shadow-none
|
||||
focus-visible:outline-scale-700`,
|
||||
text: `
|
||||
text-scale-1200
|
||||
hover:bg-scale-500
|
||||
shadow-none
|
||||
focus-visible:outline-scale-700`,
|
||||
danger: `
|
||||
text-red-1100
|
||||
bg-red-200
|
||||
bordershadow-red-700 hover:bordershadow-red-900
|
||||
hover:bg-red-900
|
||||
hover:text-lo-contrast
|
||||
focus-visible:outline-red-700
|
||||
shadow-sm`,
|
||||
warning: `
|
||||
text-amber-1100
|
||||
bg-amber-200
|
||||
bordershadow-amber-700 hover:bordershadow-amber-900
|
||||
hover:bg-amber-900
|
||||
hover:text-hi-contrast
|
||||
focus-visible:outline-amber-700
|
||||
shadow-sm`,
|
||||
},
|
||||
block: {
|
||||
true: 'w-full flex items-center justify-center',
|
||||
},
|
||||
size: {
|
||||
...sizes,
|
||||
},
|
||||
overlay: {
|
||||
base: `absolute inset-0 bg-scale-200 opacity-50`,
|
||||
container: `fixed inset-0 transition-opacity`,
|
||||
},
|
||||
disabled: {
|
||||
true: 'opacity-50 cursor-not-allowed pointer-events-none',
|
||||
},
|
||||
defaultVariants: {
|
||||
// variant: 'default',
|
||||
// size: 'default',
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export type LoadingVariantProps = VariantProps<typeof loadingVariants>
|
||||
const loadingVariants = cva('', {
|
||||
variants: {
|
||||
loading: {
|
||||
default: '',
|
||||
true: `animate-spin`,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export interface ButtonProps
|
||||
// omit `type` as we use it to change type of button
|
||||
// replaced with `htmlType`
|
||||
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type'>,
|
||||
// omit 'disabled' as it is included in HTMLButtonElement
|
||||
Omit<ButtonVariantProps, 'disabled'>,
|
||||
LoadingVariantProps {
|
||||
asChild?: boolean
|
||||
type?: ButtonVariantProps['type']
|
||||
htmlType?: React.ButtonHTMLAttributes<HTMLButtonElement>['type']
|
||||
icon?: React.ReactNode
|
||||
iconLeft?: React.ReactNode
|
||||
iconRight?: React.ReactNode
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ asChild = false, size = 'small', type = 'primary', ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : 'button'
|
||||
|
||||
const { className, disabled, loading, icon, iconLeft, iconRight } = props
|
||||
|
||||
const showIcon = loading || icon
|
||||
|
||||
// decrecating 'showIcon' for rightIcon
|
||||
const _iconLeft: React.ReactNode = icon ?? iconLeft
|
||||
|
||||
const buttonContent = (
|
||||
<>
|
||||
{showIcon &&
|
||||
(loading ? (
|
||||
<IconLoader size={size} className={cn(loadingVariants({ loading }))} />
|
||||
) : _iconLeft ? (
|
||||
<IconContext.Provider value={{ contextSize: size }}>{_iconLeft}</IconContext.Provider>
|
||||
) : null)}
|
||||
{props.children && <span className={'truncate'}>{props.children}</span>}
|
||||
{iconRight && !loading && (
|
||||
<IconContext.Provider value={{ contextSize: size }}>{iconRight}</IconContext.Provider>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ type, size, disabled }), className)}
|
||||
ref={ref}
|
||||
type={props.htmlType}
|
||||
{...props}
|
||||
>
|
||||
{buttonContent}
|
||||
</Comp>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
Button.displayName = 'Button'
|
||||
|
||||
export { Button, buttonVariants }
|
||||
@@ -1,187 +0,0 @@
|
||||
// Inspired by react-hot-toast library
|
||||
import * as React from 'react'
|
||||
|
||||
import { ToastActionElement, type ToastProps } from '@ui/components/shadcn/toast'
|
||||
|
||||
const TOAST_LIMIT = 1
|
||||
const TOAST_REMOVE_DELAY = 1000000
|
||||
|
||||
type ToasterToast = ToastProps & {
|
||||
id: string
|
||||
title?: React.ReactNode
|
||||
description?: React.ReactNode
|
||||
action?: ToastActionElement
|
||||
}
|
||||
|
||||
const actionTypes = {
|
||||
ADD_TOAST: 'ADD_TOAST',
|
||||
UPDATE_TOAST: 'UPDATE_TOAST',
|
||||
DISMISS_TOAST: 'DISMISS_TOAST',
|
||||
REMOVE_TOAST: 'REMOVE_TOAST',
|
||||
} as const
|
||||
|
||||
let count = 0
|
||||
|
||||
function genId() {
|
||||
count = (count + 1) % Number.MAX_VALUE
|
||||
return count.toString()
|
||||
}
|
||||
|
||||
type ActionType = typeof actionTypes
|
||||
|
||||
type Action =
|
||||
| {
|
||||
type: ActionType['ADD_TOAST']
|
||||
toast: ToasterToast
|
||||
}
|
||||
| {
|
||||
type: ActionType['UPDATE_TOAST']
|
||||
toast: Partial<ToasterToast>
|
||||
}
|
||||
| {
|
||||
type: ActionType['DISMISS_TOAST']
|
||||
toastId?: ToasterToast['id']
|
||||
}
|
||||
| {
|
||||
type: ActionType['REMOVE_TOAST']
|
||||
toastId?: ToasterToast['id']
|
||||
}
|
||||
|
||||
interface State {
|
||||
toasts: ToasterToast[]
|
||||
}
|
||||
|
||||
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
|
||||
|
||||
const addToRemoveQueue = (toastId: string) => {
|
||||
if (toastTimeouts.has(toastId)) {
|
||||
return
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
toastTimeouts.delete(toastId)
|
||||
dispatch({
|
||||
type: 'REMOVE_TOAST',
|
||||
toastId: toastId,
|
||||
})
|
||||
}, TOAST_REMOVE_DELAY)
|
||||
|
||||
toastTimeouts.set(toastId, timeout)
|
||||
}
|
||||
|
||||
export const reducer = (state: State, action: Action): State => {
|
||||
switch (action.type) {
|
||||
case 'ADD_TOAST':
|
||||
return {
|
||||
...state,
|
||||
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
||||
}
|
||||
|
||||
case 'UPDATE_TOAST':
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) => (t.id === action.toast.id ? { ...t, ...action.toast } : t)),
|
||||
}
|
||||
|
||||
case 'DISMISS_TOAST': {
|
||||
const { toastId } = action
|
||||
|
||||
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
||||
// but I'll keep it here for simplicity
|
||||
if (toastId) {
|
||||
addToRemoveQueue(toastId)
|
||||
} else {
|
||||
state.toasts.forEach((toast) => {
|
||||
addToRemoveQueue(toast.id)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === toastId || toastId === undefined
|
||||
? {
|
||||
...t,
|
||||
open: false,
|
||||
}
|
||||
: t
|
||||
),
|
||||
}
|
||||
}
|
||||
case 'REMOVE_TOAST':
|
||||
if (action.toastId === undefined) {
|
||||
return {
|
||||
...state,
|
||||
toasts: [],
|
||||
}
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const listeners: Array<(state: State) => void> = []
|
||||
|
||||
let memoryState: State = { toasts: [] }
|
||||
|
||||
function dispatch(action: Action) {
|
||||
memoryState = reducer(memoryState, action)
|
||||
listeners.forEach((listener) => {
|
||||
listener(memoryState)
|
||||
})
|
||||
}
|
||||
|
||||
interface Toast extends Omit<ToasterToast, 'id'> {}
|
||||
|
||||
function toast({ ...props }: Toast) {
|
||||
const id = genId()
|
||||
|
||||
const update = (props: ToasterToast) =>
|
||||
dispatch({
|
||||
type: 'UPDATE_TOAST',
|
||||
toast: { ...props, id },
|
||||
})
|
||||
const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id })
|
||||
|
||||
dispatch({
|
||||
type: 'ADD_TOAST',
|
||||
toast: {
|
||||
...props,
|
||||
id,
|
||||
open: true,
|
||||
onOpenChange: (open) => {
|
||||
if (!open) dismiss()
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
id: id,
|
||||
dismiss,
|
||||
update,
|
||||
}
|
||||
}
|
||||
|
||||
function useToast() {
|
||||
const [state, setState] = React.useState<State>(memoryState)
|
||||
|
||||
React.useEffect(() => {
|
||||
listeners.push(setState)
|
||||
return () => {
|
||||
const index = listeners.indexOf(setState)
|
||||
if (index > -1) {
|
||||
listeners.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}, [state])
|
||||
|
||||
return {
|
||||
...state,
|
||||
toast,
|
||||
dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }),
|
||||
}
|
||||
}
|
||||
|
||||
export { useToast, toast }
|
||||
Reference in new issue
Block a user