mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-03 04:43:01 +00:00
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:
@@ -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?.()
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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}
|
||||
/>
|
||||
)
|
||||
|
||||
Vendored
+1
@@ -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!",
|
||||
|
||||
Vendored
+1
@@ -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 !",
|
||||
|
||||
Vendored
+1
@@ -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!": "内部サーバーエラー!",
|
||||
|
||||
Vendored
+1
@@ -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!": "Внутренняя ошибка сервера!",
|
||||
|
||||
Vendored
+1
@@ -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
@@ -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!": "內部伺服器錯誤!",
|
||||
|
||||
Vendored
+1
@@ -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!": "内部服务器错误!",
|
||||
|
||||
Reference in New Issue
Block a user