fix: restore nested dropdown sections for expo 55 on iOS using nested ContextMenus

This commit is contained in:
Fredrik Burmester
2026-05-30 10:13:40 +02:00
parent 62c86533b1
commit 769c7a2432
2 changed files with 94 additions and 44 deletions

View File

@@ -1,4 +1,4 @@
import { Button, ContextMenu, Host, Picker } from "@expo/ui/swift-ui";
import { Button, ContextMenu, Host } from "@expo/ui/swift-ui";
import { Ionicons } from "@expo/vector-icons";
import { BottomSheetScrollView } from "@gorhom/bottom-sheet";
import React, { useEffect } from "react";
@@ -254,23 +254,39 @@ const PlatformDropdownComponent = ({
// Otherwise render as individual buttons
if (radioOptions.length > 0) {
if (group.title) {
// Use Picker for grouped options
// Use a nested ContextMenu as a submenu for grouped options
const selectedOption = radioOptions.find(
(opt) => opt.selected,
);
const displayTitle = selectedOption
? `${group.title}: ${selectedOption.label}`
: group.title;
items.push(
<Picker
key={`picker-${groupIndex}`}
label={group.title}
options={radioOptions.map((opt) => opt.label)}
variant='menu'
selectedIndex={radioOptions.findIndex(
(opt) => opt.selected,
)}
onOptionSelected={(event: any) => {
const index = event.nativeEvent.index;
const selectedOption = radioOptions[index];
selectedOption?.onPress();
onOptionSelect?.(selectedOption?.value);
}}
/>,
<ContextMenu key={`submenu-${groupIndex}`}>
<ContextMenu.Trigger>
<Button>{displayTitle}</Button>
</ContextMenu.Trigger>
<ContextMenu.Items>
{radioOptions.map((option, optionIndex) => (
<Button
key={`radio-${groupIndex}-${optionIndex}`}
systemImage={
option.selected
? "checkmark.circle.fill"
: "circle"
}
onPress={() => {
option.onPress();
onOptionSelect?.(option.value);
}}
disabled={option.disabled}
>
{option.label}
</Button>
))}
</ContextMenu.Items>
</ContextMenu>,
);
} else {
// Render radio options as direct buttons

View File

@@ -1,4 +1,4 @@
import { Button, ContextMenu, Host, Picker } from "@expo/ui/swift-ui";
import { Button, ContextMenu, Host } from "@expo/ui/swift-ui";
import { Platform, View } from "react-native";
import { FilterButton } from "@/components/filters/FilterButton";
import { JellyseerrSearchSort } from "@/components/jellyseerr/JellyseerrIndexPage";
@@ -49,32 +49,66 @@ export const DiscoverFilters: React.FC<DiscoverFiltersProps> = ({
></Button>
</ContextMenu.Trigger>
<ContextMenu.Items>
<Picker
label={t("library.filters.sort_by")}
options={sortOptions.map((item) =>
t(`home.settings.plugins.jellyseerr.order_by.${item}`),
)}
variant='menu'
selectedIndex={sortOptions.indexOf(
jellyseerrOrderBy as unknown as string,
)}
onOptionSelected={(event: any) => {
const index = event.nativeEvent.index;
setJellyseerrOrderBy(
sortOptions[index] as unknown as JellyseerrSearchSort,
);
}}
/>
<Picker
label={t("library.filters.sort_order")}
options={orderOptions.map((item) => t(`library.filters.${item}`))}
variant='menu'
selectedIndex={orderOptions.indexOf(jellyseerrSortOrder)}
onOptionSelected={(event: any) => {
const index = event.nativeEvent.index;
setJellyseerrSortOrder(orderOptions[index]);
}}
/>
<ContextMenu>
<ContextMenu.Trigger>
<Button>
{`${t("library.filters.sort_by")}: ${t(
`home.settings.plugins.jellyseerr.order_by.${jellyseerrOrderBy}`,
)}`}
</Button>
</ContextMenu.Trigger>
<ContextMenu.Items>
{sortOptions.map((item) => {
const label = t(
`home.settings.plugins.jellyseerr.order_by.${item}`,
);
const isSelected =
jellyseerrOrderBy ===
(item as unknown as JellyseerrSearchSort);
return (
<Button
key={item}
systemImage={
isSelected ? "checkmark.circle.fill" : "circle"
}
onPress={() =>
setJellyseerrOrderBy(
item as unknown as JellyseerrSearchSort,
)
}
>
{label}
</Button>
);
})}
</ContextMenu.Items>
</ContextMenu>
<ContextMenu>
<ContextMenu.Trigger>
<Button>
{`${t("library.filters.sort_order")}: ${t(
`library.filters.${jellyseerrSortOrder}`,
)}`}
</Button>
</ContextMenu.Trigger>
<ContextMenu.Items>
{orderOptions.map((item) => {
const label = t(`library.filters.${item}`);
const isSelected = jellyseerrSortOrder === item;
return (
<Button
key={item}
systemImage={
isSelected ? "checkmark.circle.fill" : "circle"
}
onPress={() => setJellyseerrSortOrder(item)}
>
{label}
</Button>
);
})}
</ContextMenu.Items>
</ContextMenu>
</ContextMenu.Items>
</ContextMenu>
</Host>