fix(web): restore DropdownMenuItem onSelect bridge and add missing Internal ID locale key

The design-system consolidation refactor dropped the onSelect-to-onClick
bridge for Base UI menu items, silently breaking menu actions such as
'Delete All Disabled' on the channels page, and removed the 'Internal ID'
translation key still used by the task details dialog.
This commit is contained in:
t0ng7u
2026-07-12 02:58:56 +08:00
parent bff42764f4
commit baf668c48d
10 changed files with 100 additions and 1 deletions
+25
View File
@@ -0,0 +1,25 @@
import type * as React from 'react'
export type DropdownMenuItemSelectEvent = React.MouseEvent<HTMLElement> & {
preventBaseUIHandler?: () => void
}
export type DropdownMenuItemSelectHandler = (
event: DropdownMenuItemSelectEvent
) => void
export function handleDropdownMenuItemSelect(
event: DropdownMenuItemSelectEvent,
onClick?: React.MouseEventHandler<HTMLElement>,
onSelect?: DropdownMenuItemSelectHandler
) {
onClick?.(event)
if (!event.defaultPrevented) {
onSelect?.(event)
}
if (event.defaultPrevented) {
event.preventBaseUIHandler?.()
}
}
+51
View File
@@ -0,0 +1,51 @@
import assert from 'node:assert/strict'
import { describe, test } from 'node:test'
import { handleDropdownMenuItemSelect } from './dropdown-menu-events'
function createMenuEvent() {
let defaultPrevented = false
let baseUIHandlerPrevented = false
return {
get defaultPrevented() {
return defaultPrevented
},
preventDefault() {
defaultPrevented = true
},
preventBaseUIHandler() {
baseUIHandlerPrevented = true
},
get baseUIHandlerPrevented() {
return baseUIHandlerPrevented
},
} as unknown as Parameters<typeof handleDropdownMenuItemSelect>[0] & {
baseUIHandlerPrevented: boolean
}
}
describe('DropdownMenuItem onSelect compatibility', () => {
test('calls the Radix-style onSelect handler on item click', () => {
const event = createMenuEvent()
let selected = false
handleDropdownMenuItemSelect(event, undefined, () => {
selected = true
})
assert.equal(selected, true)
assert.equal(event.baseUIHandlerPrevented, false)
})
test('keeps the Base UI menu open when onSelect prevents default', () => {
const event = createMenuEvent()
handleDropdownMenuItemSelect(event, undefined, (selectEvent) => {
selectEvent.preventDefault()
})
assert.equal(event.defaultPrevented, true)
assert.equal(event.baseUIHandlerPrevented, true)
})
})
+17 -1
View File
@@ -23,6 +23,11 @@ import * as React from 'react'
import { cn } from '@/lib/utils'
import {
handleDropdownMenuItemSelect,
type DropdownMenuItemSelectHandler,
} from './dropdown-menu-events'
function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
return <MenuPrimitive.Root data-slot='dropdown-menu' {...props} />
}
@@ -97,11 +102,21 @@ function DropdownMenuItem({
className,
inset,
variant = 'default',
onClick,
onSelect,
...props
}: MenuPrimitive.Item.Props & {
}: Omit<MenuPrimitive.Item.Props, 'onSelect'> & {
inset?: boolean
variant?: 'default' | 'destructive'
onSelect?: DropdownMenuItemSelectHandler
}) {
const handleClick = React.useCallback(
(event: React.MouseEvent<HTMLElement>) => {
handleDropdownMenuItemSelect(event, onClick, onSelect)
},
[onClick, onSelect]
)
return (
<MenuPrimitive.Item
data-slot='dropdown-menu-item'
@@ -111,6 +126,7 @@ function DropdownMenuItem({
"group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
className
)}
onClick={onClick || onSelect ? handleClick : undefined}
{...props}
/>
)
+1
View File
@@ -2322,6 +2322,7 @@
"Inter-group overrides": "Inter-group overrides",
"Inter-group ratio overrides": "Inter-group ratio overrides",
"Interface Language": "Interface Language",
"Internal ID": "Internal ID",
"Internal Notes": "Internal Notes",
"Internal notes (not shown to users)": "Internal notes (not shown to users)",
"Internal Server Error!": "Internal Server Error!",
+1
View File
@@ -2322,6 +2322,7 @@
"Inter-group overrides": "Dérogations inter-groupes",
"Inter-group ratio overrides": "Dérogations de ratio inter-groupes",
"Interface Language": "Langue de l'interface",
"Internal ID": "ID interne",
"Internal Notes": "Notes internes",
"Internal notes (not shown to users)": "Notes internes (non visibles par les utilisateurs)",
"Internal Server Error!": "Erreur interne du serveur !",
+1
View File
@@ -2322,6 +2322,7 @@
"Inter-group overrides": "グループ間上書き",
"Inter-group ratio overrides": "グループ間比率上書き",
"Interface Language": "インターフェース言語",
"Internal ID": "内部ID",
"Internal Notes": "内部メモ",
"Internal notes (not shown to users)": ":内部メモ(ユーザーには表示されません)",
"Internal Server Error!": "内部サーバーエラー!",
+1
View File
@@ -2322,6 +2322,7 @@
"Inter-group overrides": "Переопределения между группами",
"Inter-group ratio overrides": "Переопределения соотношений между группами",
"Interface Language": "Язык интерфейса",
"Internal ID": "Внутренний ID",
"Internal Notes": "Внутренние заметки",
"Internal notes (not shown to users)": "Внутренние заметки (не показываются пользователям)",
"Internal Server Error!": "Внутренняя ошибка сервера!",
+1
View File
@@ -2322,6 +2322,7 @@
"Inter-group overrides": "Ghi đè liên nhóm",
"Inter-group ratio overrides": "Tỷ lệ liên nhóm ghi đè",
"Interface Language": "Ngôn ngữ giao diện",
"Internal ID": "ID nội bộ",
"Internal Notes": "Ghi chú nội bộ",
"Internal notes (not shown to users)": "Ghi chú nội bộ (không hiển thị cho người dùng)",
"Internal Server Error!": "Lỗi máy chủ nội bộ!",
+1
View File
@@ -2322,6 +2322,7 @@
"Inter-group overrides": "分組間覆蓋",
"Inter-group ratio overrides": "分組間比例覆蓋",
"Interface Language": "介面語言",
"Internal ID": "內部 ID",
"Internal Notes": "內部備註",
"Internal notes (not shown to users)": "內部備註(不顯示給用戶)",
"Internal Server Error!": "內部伺服器錯誤!",
+1
View File
@@ -2322,6 +2322,7 @@
"Inter-group overrides": "分组间覆盖",
"Inter-group ratio overrides": "分组间比例覆盖",
"Interface Language": "界面语言",
"Internal ID": "内部 ID",
"Internal Notes": "内部备注",
"Internal notes (not shown to users)": "内部备注(不显示给用户)",
"Internal Server Error!": "内部服务器错误!",