Files
supabase/apps/studio/components/ui/Resource/ResourceItem.tsx
Gildas Garcia 96d43099bb chore: refactor Button API so that it can be used a standard button (#46880)
## Problem

Our `<Button>` component breaks the default `button` contract by
redefining the `type` prop to set its variant (`primary`, `default`,
etc) instead of the button type (`submit`, `button`, etc).
This is confusing and forces to write more code when using it with
shadcn components that expect/inject the standard button props.

## Solution

- rename the `type` prop to `variant`
- rename the `htmlType` prop to `type`
- propagate the changes where necessary
- format code

## How to test

As this is just prop renaming, if it builds it's ok

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2026-06-16 23:59:58 +02:00

136 lines
3.2 KiB
TypeScript

import { ChevronRight, MoreVertical } from 'lucide-react'
import Link from 'next/link'
import { forwardRef, HTMLAttributes, KeyboardEvent, ReactNode } from 'react'
import {
Button,
CardContent,
cn,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from 'ui'
export interface ResourceAction {
label: string
onClick: () => void
}
export interface ResourceItemProps extends HTMLAttributes<HTMLDivElement> {
media?: ReactNode
meta?: ReactNode
onClick?: () => void
children?: ReactNode
actions?: ResourceAction[]
href?: string
target?: string
rel?: string
}
export const ResourceItem = forwardRef<HTMLDivElement, ResourceItemProps>(
(
{
media,
meta,
onClick,
children,
className,
actions,
href,
target,
rel,
onKeyDown,
role,
tabIndex,
...props
},
ref
) => {
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
onKeyDown?.(event)
if (event.defaultPrevented || !onClick || event.target !== event.currentTarget) return
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault()
onClick()
}
}
const content = (
<>
{media && (
<div className="text-foreground-light flex items-center justify-center">{media}</div>
)}
<div className="flex-1">{children}</div>
{meta && <div>{meta}</div>}
{actions && actions.length > 0 ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="text"
className="px-1"
icon={<MoreVertical size={16} />}
onClick={(e) => {
e.stopPropagation()
}}
/>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{actions.map((action) => (
<DropdownMenuItem
key={action.label}
onClick={(e) => {
e.stopPropagation()
action.onClick()
}}
>
{action.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
) : (
onClick && <ChevronRight strokeWidth={1.5} size={16} />
)}
</>
)
const rootClassName = cn(
'flex items-center justify-between text-sm gap-4',
'border-b-0!',
(onClick || href) && 'cursor-pointer transition-colors duration-150 hover:bg-surface-200',
className
)
if (href) {
return (
<Link
href={href}
target={target}
rel={rel}
className={cn('py-4 px-(--card-padding-x) border-b last:border-none', rootClassName)}
>
{content}
</Link>
)
}
return (
<CardContent
ref={ref}
className={rootClassName}
onClick={onClick}
onKeyDown={handleKeyDown}
role={onClick ? 'button' : role}
tabIndex={onClick ? (tabIndex ?? 0) : tabIndex}
{...props}
>
{content}
</CardContent>
)
}
)
ResourceItem.displayName = 'ResourceItem'