Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add dismiss backdrop to native dropdowns (#4711)

authored by

dan and committed by
GitHub
a9fe87b8 1a037d35

+98 -65
+98 -65
src/view/com/util/forms/NativeDropdown.tsx
··· 1 1 import React from 'react' 2 + import {Platform, Pressable, StyleSheet, View, ViewStyle} from 'react-native' 3 + import {IconProp} from '@fortawesome/fontawesome-svg-core' 2 4 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 3 5 import * as DropdownMenu from 'zeego/dropdown-menu' 4 - import {Pressable, StyleSheet, Platform, View, ViewStyle} from 'react-native' 5 - import {IconProp} from '@fortawesome/fontawesome-svg-core' 6 6 import {MenuItemCommonProps} from 'zeego/lib/typescript/menu' 7 + 8 + import {HITSLOP_10} from 'lib/constants' 7 9 import {usePalette} from 'lib/hooks/usePalette' 8 - import {isWeb} from 'platform/detection' 9 10 import {useTheme} from 'lib/ThemeContext' 10 - import {HITSLOP_10} from 'lib/constants' 11 + import {isIOS, isWeb} from 'platform/detection' 12 + import {Portal} from '#/components/Portal' 11 13 12 14 // Custom Dropdown Menu Components 13 15 // == ··· 169 171 }: React.PropsWithChildren<Props>) { 170 172 const pal = usePalette('default') 171 173 const theme = useTheme() 174 + const [isOpen, setIsOpen] = React.useState(false) 172 175 const dropDownBackgroundColor = 173 176 theme.colorScheme === 'dark' ? pal.btn : pal.viewLight 174 177 175 178 return ( 176 - <DropdownMenuRoot> 177 - <DropdownMenuTrigger 178 - action="press" 179 - testID={testID} 180 - accessibilityLabel={accessibilityLabel} 181 - accessibilityHint={accessibilityHint}> 182 - {children} 183 - </DropdownMenuTrigger> 184 - <DropdownMenuContent 185 - style={[styles.content, dropDownBackgroundColor]} 186 - loop> 187 - {items.map((item, index) => { 188 - if (item.label === 'separator') { 179 + <> 180 + {isIOS && isOpen && ( 181 + <Portal> 182 + <Backdrop /> 183 + </Portal> 184 + )} 185 + <DropdownMenuRoot onOpenWillChange={setIsOpen}> 186 + <DropdownMenuTrigger 187 + action="press" 188 + testID={testID} 189 + accessibilityLabel={accessibilityLabel} 190 + accessibilityHint={accessibilityHint}> 191 + {children} 192 + </DropdownMenuTrigger> 193 + <DropdownMenuContent 194 + style={[styles.content, dropDownBackgroundColor]} 195 + loop> 196 + {items.map((item, index) => { 197 + if (item.label === 'separator') { 198 + return ( 199 + <DropdownMenuSeparator 200 + key={getKey(item.label, index, item.testID)} 201 + /> 202 + ) 203 + } 204 + if (index > 1 && items[index - 1].label === 'separator') { 205 + return ( 206 + <DropdownMenu.Group 207 + key={getKey(item.label, index, item.testID)}> 208 + <DropdownMenuItem 209 + key={getKey(item.label, index, item.testID)} 210 + onSelect={item.onPress}> 211 + <DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle> 212 + {item.icon && ( 213 + <DropdownMenuItemIcon 214 + ios={item.icon.ios} 215 + // androidIconName={item.icon.android} TODO: Add custom android icon support, because these ones are based on https://developer.android.com/reference/android/R.drawable.html and they are ugly 216 + > 217 + <FontAwesomeIcon 218 + icon={item.icon.web} 219 + size={20} 220 + style={[pal.text]} 221 + /> 222 + </DropdownMenuItemIcon> 223 + )} 224 + </DropdownMenuItem> 225 + </DropdownMenu.Group> 226 + ) 227 + } 189 228 return ( 190 - <DropdownMenuSeparator 229 + <DropdownMenuItem 191 230 key={getKey(item.label, index, item.testID)} 192 - /> 193 - ) 194 - } 195 - if (index > 1 && items[index - 1].label === 'separator') { 196 - return ( 197 - <DropdownMenu.Group key={getKey(item.label, index, item.testID)}> 198 - <DropdownMenuItem 199 - key={getKey(item.label, index, item.testID)} 200 - onSelect={item.onPress}> 201 - <DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle> 202 - {item.icon && ( 203 - <DropdownMenuItemIcon 204 - ios={item.icon.ios} 205 - // androidIconName={item.icon.android} TODO: Add custom android icon support, because these ones are based on https://developer.android.com/reference/android/R.drawable.html and they are ugly 206 - > 207 - <FontAwesomeIcon 208 - icon={item.icon.web} 209 - size={20} 210 - style={[pal.text]} 211 - /> 212 - </DropdownMenuItemIcon> 213 - )} 214 - </DropdownMenuItem> 215 - </DropdownMenu.Group> 231 + onSelect={item.onPress}> 232 + <DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle> 233 + {item.icon && ( 234 + <DropdownMenuItemIcon 235 + ios={item.icon.ios} 236 + // androidIconName={item.icon.android} 237 + > 238 + <FontAwesomeIcon 239 + icon={item.icon.web} 240 + size={20} 241 + style={[pal.text]} 242 + /> 243 + </DropdownMenuItemIcon> 244 + )} 245 + </DropdownMenuItem> 216 246 ) 217 - } 218 - return ( 219 - <DropdownMenuItem 220 - key={getKey(item.label, index, item.testID)} 221 - onSelect={item.onPress}> 222 - <DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle> 223 - {item.icon && ( 224 - <DropdownMenuItemIcon 225 - ios={item.icon.ios} 226 - // androidIconName={item.icon.android} 227 - > 228 - <FontAwesomeIcon 229 - icon={item.icon.web} 230 - size={20} 231 - style={[pal.text]} 232 - /> 233 - </DropdownMenuItemIcon> 234 - )} 235 - </DropdownMenuItem> 236 - ) 237 - })} 238 - </DropdownMenuContent> 239 - </DropdownMenuRoot> 247 + })} 248 + </DropdownMenuContent> 249 + </DropdownMenuRoot> 250 + </> 251 + ) 252 + } 253 + 254 + function Backdrop() { 255 + // Not visible but it eats the click outside. 256 + // Only necessary for iOS. 257 + return ( 258 + <Pressable 259 + accessibilityRole="button" 260 + accessibilityLabel="Dialog backdrop" 261 + accessibilityHint="Press the backdrop to close the dialog" 262 + style={{ 263 + top: 0, 264 + left: 0, 265 + right: 0, 266 + bottom: 0, 267 + position: 'absolute', 268 + }} 269 + onPress={() => { 270 + /* noop */ 271 + }} 272 + /> 240 273 ) 241 274 } 242 275