fix (app): mobile sidebar web interactions (#900)

* fix mobile sidebar web interactions

* fix(app): restore button role on sidebar project row

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
This commit is contained in:
nikuscs
2026-05-15 13:38:43 +00:00
committed by GitHub
co-authored by Mohamed Boudra
parent e309d82b41
commit 35c582913d
4 changed files with 65 additions and 11 deletions
@@ -89,6 +89,12 @@ function SortableItem<T>({
}),
[combinedTransform, transition, isDragging],
);
const {
role: _dragRole,
tabIndex: _dragTabIndex,
"aria-roledescription": _dragRoleDescription,
...dragHandleAttributes
} = attributes as unknown as Record<string, unknown>;
const info: DraggableRenderItemInfo<T> = {
item,
@@ -97,7 +103,7 @@ function SortableItem<T>({
isActive: activeId === id,
dragHandleProps: useDragHandle
? {
attributes: attributes as unknown as Record<string, unknown>,
attributes: dragHandleAttributes,
listeners: listeners as unknown as Record<string, unknown>,
setActivatorNodeRef: setActivatorNodeRef as unknown as (node: unknown) => void,
}
+32 -1
View File
@@ -1,5 +1,5 @@
import { router, usePathname } from "expo-router";
import { FolderPlus, MessagesSquare, Settings } from "lucide-react-native";
import { FolderPlus, MessagesSquare, Settings, X } from "lucide-react-native";
import {
type Dispatch,
memo,
@@ -679,6 +679,25 @@ function MobileSidebar({
isActive={isSessionsActive}
testID="sidebar-sessions"
/>
<Pressable
style={styles.mobileCloseButton}
onPress={closeToAgent}
testID="sidebar-close"
nativeID="sidebar-close"
accessible
accessibilityRole="button"
accessibilityLabel="Close sidebar"
hitSlop={8}
>
{({ hovered, pressed }) => (
<X
size={theme.iconSize.md}
color={
hovered || pressed ? theme.colors.foreground : theme.colors.foregroundMuted
}
/>
)}
</Pressable>
{isInitialLoad ? (
<SidebarAgentListSkeleton />
@@ -888,6 +907,18 @@ const styles = StyleSheet.create((theme) => ({
flex: 1,
minHeight: 0,
},
mobileCloseButton: {
position: "absolute",
top: theme.spacing[3],
right: theme.spacing[4],
zIndex: 2,
width: 32,
height: 32,
alignItems: "center",
justifyContent: "center",
borderRadius: theme.borderRadius.lg,
backgroundColor: theme.colors.surfaceSidebar,
},
desktopSidebarBorder: {
borderRightWidth: 1,
borderRightColor: theme.colors.border,
@@ -594,7 +594,7 @@ function ProjectKebabMenu({
<DropdownMenuTrigger
hitSlop={8}
style={projectKebabStyle}
accessibilityRole="button"
accessibilityRole={platformIsWeb ? undefined : "button"}
accessibilityLabel="Project actions"
testID={`sidebar-project-kebab-${projectKey}`}
>
@@ -725,7 +725,7 @@ function WorkspaceKebabMenu({
<DropdownMenuTrigger
hitSlop={8}
style={workspaceKebabStyle}
accessibilityRole="button"
accessibilityRole={platformIsWeb ? undefined : "button"}
accessibilityLabel="Workspace actions"
testID={`sidebar-workspace-kebab-${workspaceKey}`}
>
@@ -895,7 +895,7 @@ function NewWorktreeButton({
style={pressableStyle}
onPress={handlePress}
disabled={loading}
accessibilityRole="button"
accessibilityRole={platformIsWeb ? undefined : "button"}
accessibilityLabel={`Create a new workspace for ${displayName}`}
testID={testID}
>
@@ -1187,6 +1187,12 @@ function ProjectHeaderRow({
drag,
menuController,
});
const {
role: _dragRole,
tabIndex: _dragTabIndex,
"aria-roledescription": _dragRoleDescription,
...dragAttributes
} = dragHandleProps?.attributes ?? {};
const handlePress = useCallback(() => {
if (interaction.didLongPressRef.current) {
@@ -1250,7 +1256,7 @@ function ProjectHeaderRow({
if (menuController) {
return (
<View
{...dragHandleProps?.attributes}
{...dragAttributes}
{...dragHandleProps?.listeners}
ref={dragHandleProps?.setActivatorNodeRef as unknown as Ref<View>}
onPointerEnter={handlePointerEnter}
@@ -1258,6 +1264,7 @@ function ProjectHeaderRow({
>
<ContextMenuTrigger
enabledOnMobile={false}
accessibilityRole="button"
style={projectRowStyle}
onPressIn={interaction.handlePressIn}
onTouchMove={interaction.handleTouchMove}
@@ -1273,13 +1280,14 @@ function ProjectHeaderRow({
return (
<View
{...dragHandleProps?.attributes}
{...dragAttributes}
{...dragHandleProps?.listeners}
ref={dragHandleProps?.setActivatorNodeRef as unknown as Ref<View>}
onPointerEnter={handlePointerEnter}
onPointerLeave={handlePointerLeave}
>
<Pressable
accessibilityRole="button"
style={projectRowStyle}
onPressIn={interaction.handlePressIn}
onTouchMove={interaction.handleTouchMove}
@@ -1328,6 +1336,12 @@ function WorkspaceRowInner({
drag,
menuController,
});
const {
role: _dragRole,
tabIndex: _dragTabIndex,
"aria-roledescription": _dragRoleDescription,
...dragAttributes
} = dragHandleProps?.attributes ?? {};
const handlePress = useCallback(() => {
if (interaction.didLongPressRef.current) {
@@ -1369,7 +1383,7 @@ function WorkspaceRowInner({
return (
<WorkspaceHoverCard workspace={workspace} prHint={prHint} isDragging={isDragging}>
<View
{...dragHandleProps?.attributes}
{...dragAttributes}
{...dragHandleProps?.listeners}
ref={dragHandleProps?.setActivatorNodeRef as unknown as Ref<View>}
style={styles.workspaceRowContainer}
@@ -8,7 +8,7 @@ import {
type ReactElement,
type ReactNode,
} from "react";
import { Dimensions, Platform, Text, View } from "react-native";
import { Dimensions, Text, View } from "react-native";
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
import { StyleSheet, withUnistyles } from "react-native-unistyles";
import { CircleCheck, CircleDot, CircleX, ExternalLink } from "lucide-react-native";
@@ -23,6 +23,8 @@ import type { PrHint } from "@/git/use-pr-status-query";
import { openExternalUrl } from "@/utils/open-external-url";
import { PrBadge } from "@/components/sidebar-workspace-list";
import { useHoverSafeZone } from "@/hooks/use-hover-safe-zone";
import { useIsCompactFormFactor } from "@/constants/layout";
import { isWeb } from "@/constants/platform";
interface Rect {
x: number;
@@ -84,8 +86,9 @@ export function WorkspaceHoverCard({
isDragging,
children,
}: PropsWithChildren<WorkspaceHoverCardProps>): ReactNode {
// Desktop-only: skip on non-web platforms
if (Platform.OS !== "web") {
const isCompact = useIsCompactFormFactor();
if (!isWeb || isCompact) {
return children;
}