diff --git a/apps/desktop/layer/renderer/src/modules/app-layout/feed-column/desktop.tsx b/apps/desktop/layer/renderer/src/modules/app-layout/feed-column/desktop.tsx
index 8b28b5be5..0500bf42f 100644
--- a/apps/desktop/layer/renderer/src/modules/app-layout/feed-column/desktop.tsx
+++ b/apps/desktop/layer/renderer/src/modules/app-layout/feed-column/desktop.tsx
@@ -1,6 +1,6 @@
import type { DragEndEvent } from "@dnd-kit/core"
import { DndContext, PointerSensor, pointerWithin, useSensor, useSensors } from "@dnd-kit/core"
-import { useGlobalFocusableScope } from "@follow/components/common/Focusable/hooks.js"
+import { useGlobalFocusableScopeSelector } from "@follow/components/common/Focusable/hooks.js"
import { PanelSplitter } from "@follow/components/ui/divider/index.js"
import { Kbd } from "@follow/components/ui/kbd/Kbd.js"
import { RootPortal } from "@follow/components/ui/portal/index.jsx"
@@ -238,11 +238,14 @@ const FeedResponsiveResizerContainer = ({
}
}, [feedColumnShow])
- const activeScopes = useGlobalFocusableScope()
+ const when = useGlobalFocusableScopeSelector(
+ // eslint-disable-next-line @eslint-react/hooks-extra/no-unnecessary-use-callback
+ React.useCallback((activeScope) => !activeScope.or(...FloatingLayerScope), []),
+ )
useCommandBinding({
commandId: COMMAND_ID.layout.toggleSubscriptionColumn,
- when: !activeScopes.or(...FloatingLayerScope),
+ when,
})
const [delayShowSplitter, setDelayShowSplitter] = useState(feedColumnShow)
diff --git a/apps/desktop/layer/renderer/src/modules/app-layout/subview/index.electron.tsx b/apps/desktop/layer/renderer/src/modules/app-layout/subview/index.electron.tsx
index a6f5ae4a0..619d1a1d9 100644
--- a/apps/desktop/layer/renderer/src/modules/app-layout/subview/index.electron.tsx
+++ b/apps/desktop/layer/renderer/src/modules/app-layout/subview/index.electron.tsx
@@ -1,5 +1,5 @@
import { getReadonlyRoute } from "@follow/components/atoms/route.js"
-import { useGlobalFocusableScope } from "@follow/components/common/Focusable/hooks.js"
+import { useGlobalFocusableHasScope } from "@follow/components/common/Focusable/hooks.js"
import { MotionButtonBase } from "@follow/components/ui/button/index.js"
import { ScrollArea } from "@follow/components/ui/scroll-area/index.js"
import { Routes } from "@follow/constants"
@@ -71,9 +71,9 @@ function SubviewLayoutInner() {
navigate(-1)
}
}
- const activeScope = useGlobalFocusableScope()
+
useHotkeys("Escape", backHandler, {
- enabled: activeScope.has(HotkeyScope.SubLayer),
+ enabled: useGlobalFocusableHasScope(HotkeyScope.SubLayer),
})
return (
diff --git a/apps/desktop/layer/renderer/src/modules/entry-column/EntryColumnShortcutHandler.tsx b/apps/desktop/layer/renderer/src/modules/entry-column/EntryColumnShortcutHandler.tsx
index 43f362836..1efdb3204 100644
--- a/apps/desktop/layer/renderer/src/modules/entry-column/EntryColumnShortcutHandler.tsx
+++ b/apps/desktop/layer/renderer/src/modules/entry-column/EntryColumnShortcutHandler.tsx
@@ -1,6 +1,6 @@
import {
useFocusActions,
- useGlobalFocusableScope,
+ useGlobalFocusableScopeSelector,
} from "@follow/components/common/Focusable/hooks.js"
import { useScrollViewElement } from "@follow/components/ui/scroll-area/hooks.js"
import { useRefValue } from "@follow/hooks"
@@ -24,9 +24,7 @@ export const EntryColumnShortcutHandler: FC<{
}> = memo(({ data, refetch, handleScrollTo }) => {
const dataRef = useRefValue(data!)
- const activeScope = useGlobalFocusableScope()
-
- const when = FocusablePresets.isTimeline(activeScope)
+ const when = useGlobalFocusableScopeSelector(FocusablePresets.isTimeline)
useCommandBinding({
commandId: COMMAND_ID.timeline.switchToNext,
diff --git a/apps/desktop/layer/renderer/src/modules/entry-column/components/mark-all-button.tsx b/apps/desktop/layer/renderer/src/modules/entry-column/components/mark-all-button.tsx
index cbfa4bc50..ade048a87 100644
--- a/apps/desktop/layer/renderer/src/modules/entry-column/components/mark-all-button.tsx
+++ b/apps/desktop/layer/renderer/src/modules/entry-column/components/mark-all-button.tsx
@@ -1,11 +1,11 @@
-import { useGlobalFocusableScope } from "@follow/components/common/Focusable/hooks.js"
+import { useGlobalFocusableScopeSelector } from "@follow/components/common/Focusable/hooks.js"
import { ActionButton, Button } from "@follow/components/ui/button/index.js"
import { Kbd, KbdCombined } from "@follow/components/ui/kbd/Kbd.js"
import { useCountdown } from "@follow/hooks"
import { EventBus } from "@follow/utils/event-bus"
import { cn } from "@follow/utils/utils"
import type { FC, ReactNode } from "react"
-import { useEffect, useState } from "react"
+import { useCallback, useEffect, useState } from "react"
import { useHotkeys } from "react-hotkeys-hook"
import { Trans, useTranslation } from "react-i18next"
import { toast } from "sonner"
@@ -33,10 +33,17 @@ export const MarkAllReadButton = ({
const { t } = useTranslation()
const { t: commonT } = useTranslation("common")
- const activeScope = useGlobalFocusableScope()
+ // const activeScope = useGlobalFocusableScope()
+ const when = useGlobalFocusableScopeSelector(
+ // eslint-disable-next-line @eslint-react/hooks-extra/no-unnecessary-use-callback
+ useCallback(
+ (activeScope) => activeScope.or(HotkeyScope.Timeline, HotkeyScope.SubscriptionList),
+ [],
+ ),
+ )
useCommandBinding({
commandId: COMMAND_ID.subscription.markAllAsRead,
- when: activeScope.or(HotkeyScope.Timeline, HotkeyScope.SubscriptionList),
+ when,
})
useEffect(() => {
diff --git a/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx b/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx
index d90288586..77057359a 100644
--- a/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx
+++ b/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx
@@ -1,4 +1,4 @@
-import { useGlobalFocusableScope } from "@follow/components/common/Focusable/hooks.js"
+import { useGlobalFocusableScopeSelector } from "@follow/components/common/Focusable/hooks.js"
import { useMobile } from "@follow/components/hooks/useMobile.js"
import type { FeedViewType } from "@follow/constants"
import { views } from "@follow/constants"
@@ -51,8 +51,8 @@ export const EntryItemWrapper: FC<
({ entryId }) => entryId === entry.entries.id,
[entry.entries.id],
)
- const scope = useGlobalFocusableScope()
- useContextMenuActionShortCutTrigger(actionConfigs, isActive && FocusablePresets.isTimeline(scope))
+ const when = useGlobalFocusableScopeSelector(FocusablePresets.isTimeline)
+ useContextMenuActionShortCutTrigger(actionConfigs, isActive && when)
const asRead = useEntryIsRead(entry)
const hoverMarkUnread = useGeneralSettingKey("hoverMarkUnread")
diff --git a/apps/desktop/layer/renderer/src/modules/settings/helper/EnhancedIndicator.tsx b/apps/desktop/layer/renderer/src/modules/settings/helper/EnhancedIndicator.tsx
index 129a20002..c316f6fc6 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/helper/EnhancedIndicator.tsx
+++ b/apps/desktop/layer/renderer/src/modules/settings/helper/EnhancedIndicator.tsx
@@ -8,6 +8,8 @@ import { IconTransition } from "~/components/ux/transition/icon"
export const EnhancedSettingsIndicator = () => {
const enhancedSettings = useGeneralSettingKey("enhancedSettings")
const { t } = useTranslation("settings")
+
+ if (!enhancedSettings) return null
return (
diff --git a/apps/desktop/layer/renderer/src/modules/settings/utils.ts b/apps/desktop/layer/renderer/src/modules/settings/utils.ts
index 4b79314e1..2aafb53e4 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/utils.ts
+++ b/apps/desktop/layer/renderer/src/modules/settings/utils.ts
@@ -21,6 +21,7 @@ export interface SettingPageConfig {
ctx: SettingPageContext,
serverConfigs?: ServerConfigs | null,
) => [boolean, DisableWhy]
+ viewportClassName?: string
}
export const defineSettingPageData = (config: SettingPageConfig) => ({
...config,
diff --git a/apps/desktop/layer/renderer/src/modules/subscription-column/FeedItem.tsx b/apps/desktop/layer/renderer/src/modules/subscription-column/FeedItem.tsx
index f7eb6d7d6..b566bb80e 100644
--- a/apps/desktop/layer/renderer/src/modules/subscription-column/FeedItem.tsx
+++ b/apps/desktop/layer/renderer/src/modules/subscription-column/FeedItem.tsx
@@ -1,4 +1,4 @@
-import { useGlobalFocusableScope } from "@follow/components/common/Focusable/hooks.js"
+import { useGlobalFocusableScopeSelector } from "@follow/components/common/Focusable/hooks.js"
import { useMobile } from "@follow/components/hooks/useMobile.js"
import { OouiUserAnonymous } from "@follow/components/icons/OouiUserAnonymous.jsx"
import { Button } from "@follow/components/ui/button/index.js"
@@ -120,9 +120,9 @@ const FeedItemImpl = ({ view, feedId, className, isPreview }: FeedItemProps) =>
view,
})
- const scope = useGlobalFocusableScope()
+ const when = useGlobalFocusableScopeSelector(FocusablePresets.isSubscriptionList)
- const whenTrigger = FocusablePresets.isSubscriptionList(scope) && isActive
+ const whenTrigger = when && isActive
useContextMenuActionShortCutTrigger(items, whenTrigger)
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false)
@@ -260,8 +260,8 @@ const ListItemImpl: Component = ({
const isActive = useRouteParamsSelector((routerParams) => routerParams.listId === listId)
const items = useListActions({ listId, view })
- const scope = useGlobalFocusableScope()
- useContextMenuActionShortCutTrigger(items, FocusablePresets.isSubscriptionList(scope) && isActive)
+ const when = useGlobalFocusableScopeSelector(FocusablePresets.isSubscriptionList)
+ useContextMenuActionShortCutTrigger(items, when && isActive)
const listUnread = useUnreadByListId(listId)
@@ -369,8 +369,8 @@ const InboxItemImpl: Component = ({ view, inboxId, className, ic
const isActive = useRouteParamsSelector((routerParams) => routerParams.inboxId === inboxId)
const { items } = useInboxActions({ inboxId })
- const scope = useGlobalFocusableScope()
- useContextMenuActionShortCutTrigger(items, FocusablePresets.isSubscriptionList(scope) && isActive)
+ const when = useGlobalFocusableScopeSelector(FocusablePresets.isSubscriptionList)
+ useContextMenuActionShortCutTrigger(items, when && isActive)
const inboxUnread = useUnreadById(inboxId)
diff --git a/packages/internal/components/src/common/Focusable/hooks.ts b/packages/internal/components/src/common/Focusable/hooks.ts
index 4fbdc541c..1e3163506 100644
--- a/packages/internal/components/src/common/Focusable/hooks.ts
+++ b/packages/internal/components/src/common/Focusable/hooks.ts
@@ -28,6 +28,10 @@ export const useFocusableContainerRef = () => {
return use(FocusableContainerRefContext)
}
+/**
+ * Performance issue, use `useGlobalFocusableScopeSelector` instead
+ * @deprecated use `useGlobalFocusableScopeSelector` instead
+ */
export const useGlobalFocusableScope = () => {
return useAtomValue(use(GlobalFocusableContext))
}
@@ -35,7 +39,9 @@ export const useGlobalFocusableScope = () => {
export const useGlobalFocusableHasScope = (scope: string) => {
return useGlobalFocusableScopeSelector(useCallback((v) => v.has(scope), [scope]))
}
-export const useGlobalFocusableScopeSelector = (selector: (scope: Set) => boolean) => {
+export const useGlobalFocusableScopeSelector = (
+ selector: (scope: EnhanceSet) => boolean,
+) => {
const ctx = use(GlobalFocusableContext)
return useAtomValue(useMemo(() => selectAtom(ctx, selector), [ctx, selector]))
diff --git a/packages/internal/components/src/ui/checkbox/index.tsx b/packages/internal/components/src/ui/checkbox/index.tsx
index 571651d33..cdec7eea1 100644
--- a/packages/internal/components/src/ui/checkbox/index.tsx
+++ b/packages/internal/components/src/ui/checkbox/index.tsx
@@ -57,7 +57,6 @@ function Checkbox({ className, onCheckedChange, ...props }: CheckboxProps) {
opacity: 1,
transition: {
duration: 0.2,
- delay: 0.2,
},
},
unchecked: {