fix: improve dropdown menu focus management and simplify rendering
- Introduced `useSetGlobalFocusableScope` hook to manage focus scope when the dropdown menu opens and closes. - Removed the `Focusable` wrapper from the dropdown menu content to streamline rendering. - Updated the subscription column to utilize `useGlobalFocusableScopeSelector` for better focus state management. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
119f6b5383
commit
f31d43da08
|
|
@ -1,3 +1,4 @@
|
|||
import { useSetGlobalFocusableScope } from "@follow/components/common/Focusable/hooks.js"
|
||||
import { Divider } from "@follow/components/ui/divider/Divider.js"
|
||||
import { Kbd } from "@follow/components/ui/kbd/Kbd.js"
|
||||
import { RootPortal } from "@follow/components/ui/portal/index.js"
|
||||
|
|
@ -6,15 +7,21 @@ import { cn } from "@follow/utils/utils"
|
|||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import * as React from "react"
|
||||
|
||||
import { Focusable } from "~/components/common/Focusable"
|
||||
import { HotkeyScope } from "~/constants"
|
||||
|
||||
const DropdownMenu: typeof DropdownMenuPrimitive.Root = (props) => {
|
||||
const setGlobalFocusableScope = useSetGlobalFocusableScope()
|
||||
return (
|
||||
<DropdownMenuPrimitive.Root
|
||||
{...props}
|
||||
onOpenChange={useTypeScriptHappyCallback(
|
||||
(open) => {
|
||||
if (open) {
|
||||
setGlobalFocusableScope(HotkeyScope.DropdownMenu, "append")
|
||||
} else {
|
||||
setGlobalFocusableScope(HotkeyScope.DropdownMenu, "remove")
|
||||
}
|
||||
|
||||
props.onOpenChange?.(open)
|
||||
},
|
||||
[props.onOpenChange],
|
||||
|
|
@ -91,18 +98,16 @@ const DropdownMenuContent = ({
|
|||
}) => {
|
||||
return (
|
||||
<RootPortal>
|
||||
<Focusable scope={HotkeyScope.DropdownMenu} className="contents">
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-material-medium backdrop-blur-background text-text shadow-context-menu z-[60] min-w-32 overflow-hidden rounded-[6px] border p-1",
|
||||
"motion-scale-in-75 motion-duration-150 text-body lg:animate-none",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</Focusable>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-material-medium backdrop-blur-background text-text shadow-context-menu z-[60] min-w-32 overflow-hidden rounded-[6px] border p-1",
|
||||
"motion-scale-in-75 motion-duration-150 text-body lg:animate-none",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</RootPortal>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useGlobalFocusableScope } from "@follow/components/common/Focusable/hooks.js"
|
||||
import { useGlobalFocusableScopeSelector } from "@follow/components/common/Focusable/hooks.js"
|
||||
import { ActionButton } from "@follow/components/ui/button/index.js"
|
||||
import { RootPortal } from "@follow/components/ui/portal/index.js"
|
||||
import { Routes } from "@follow/constants"
|
||||
|
|
@ -243,9 +243,15 @@ const CommandsHandler = ({
|
|||
setActive: (args: string | ((prev: string | undefined, index: number) => string)) => void
|
||||
timelineList: string[]
|
||||
}) => {
|
||||
const activeScope = useGlobalFocusableScope()
|
||||
const when =
|
||||
activeScope.or(HotkeyScope.SubscriptionList, HotkeyScope.Timeline) || activeScope.size === 0
|
||||
const when = useGlobalFocusableScopeSelector(
|
||||
// eslint-disable-next-line @eslint-react/hooks-extra/no-unnecessary-use-callback
|
||||
useCallback(
|
||||
(activeScope) =>
|
||||
activeScope.or(HotkeyScope.SubscriptionList, HotkeyScope.Timeline) ||
|
||||
activeScope.size === 0,
|
||||
[],
|
||||
),
|
||||
)
|
||||
|
||||
useCommandBinding({
|
||||
commandId: COMMAND_ID.subscription.switchTabToNext,
|
||||
|
|
@ -261,13 +267,13 @@ const CommandsHandler = ({
|
|||
return EventBus.subscribe(COMMAND_ID.subscription.switchTabToNext, () => {
|
||||
setActive((_, i) => timelineList[(i + 1) % timelineList.length]!)
|
||||
})
|
||||
}, [activeScope, setActive, timelineList])
|
||||
}, [setActive, timelineList])
|
||||
|
||||
useEffect(() => {
|
||||
return EventBus.subscribe(COMMAND_ID.subscription.switchTabToPrevious, () => {
|
||||
setActive((_, i) => timelineList[(i - 1 + timelineList.length) % timelineList.length]!)
|
||||
})
|
||||
}, [activeScope, setActive, timelineList])
|
||||
}, [setActive, timelineList])
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue