mirror of
https://github.com/langgenius/dify.git
synced 2026-03-20 05:57:59 +08:00
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.
101 lines
2.8 KiB
TypeScript
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)
|