Files
dify/web/app/components/workflow/skill/file-tree/tree/menu-item.tsx
yyh 9e10b73b54 refactor(skill): replace @remixicon/react imports with CSS icon classes
Migrate all Remixicon component imports in workflow/skill to Tailwind CSS
icon utility classes (i-ri-*), reducing JS bundle size. Update MenuItem
to accept string icon classes alongside React components. Adjust test
selectors that relied on SVG element queries.
2026-02-09 19:51:05 +08:00

101 lines
2.8 KiB
TypeScript

'use client'
import type { VariantProps } from 'class-variance-authority'
import { cva } from 'class-variance-authority'
import * as React from 'react'
import Tooltip from '@/app/components/base/tooltip'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
import { cn } from '@/utils/classnames'
const menuItemVariants = cva(
[
'flex w-full items-center gap-2 rounded-lg px-3 py-2',
'disabled:cursor-not-allowed disabled:opacity-50',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-components-input-border-active',
],
{
variants: {
variant: {
default: 'hover:bg-state-base-hover',
destructive: 'group hover:bg-state-destructive-hover',
},
},
defaultVariants: {
variant: 'default',
},
},
)
const iconVariants = cva('size-4 text-text-tertiary', {
variants: {
variant: {
default: '',
destructive: 'group-hover:text-text-destructive',
},
},
defaultVariants: {
variant: 'default',
},
})
const labelVariants = cva('text-text-secondary system-sm-regular', {
variants: {
variant: {
default: '',
destructive: 'group-hover:text-text-destructive',
},
},
defaultVariants: {
variant: 'default',
},
})
export type MenuItemProps = {
icon: React.ElementType | string
label: string
kbd?: readonly string[]
onClick: React.MouseEventHandler<HTMLButtonElement>
disabled?: boolean
tooltip?: string
} & VariantProps<typeof menuItemVariants>
const MenuItem = ({ icon: Icon, label, kbd, onClick, disabled, variant, tooltip }: MenuItemProps) => {
const handleClick = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation()
onClick(event)
}, [onClick])
return (
<button
type="button"
onClick={handleClick}
disabled={disabled}
className={cn(menuItemVariants({ variant }))}
>
{typeof Icon === 'string'
? <span className={cn(Icon, iconVariants({ variant }))} aria-hidden="true" />
: <Icon className={cn(iconVariants({ variant }))} aria-hidden="true" />}
<span className={cn(labelVariants({ variant }), 'flex-1 text-left')}>{label}</span>
{kbd && kbd.length > 0 && <ShortcutsName keys={kbd} textColor="secondary" />}
{tooltip && (
<Tooltip
popupContent={tooltip}
position="right"
>
<span
className="flex shrink-0 items-center justify-center"
onClick={(event) => {
event.preventDefault()
event.stopPropagation()
}}
>
<span className="i-ri-question-line size-4 text-text-quaternary hover:text-text-tertiary" />
</span>
</Tooltip>
)}
</button>
)
}
export default React.memo(MenuItem)