Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client

Composer - fix modals, and other tweaks (#4298)

* fix depreciated import

* add animations to old dropdown

* wrap modals in fullwindowoverlay

* move errors inside header

* add background to bottom bar and stop overlap

* nest dialogs on android

* fix android (wrap in gesturehandlerrootview)

* make borders all the same color

* revert threadgate button back to solid

authored by samuel.fm and committed by

GitHub 05b55c19 d614f6cb

+268 -220
+44 -41
src/components/Dialog/index.tsx
··· 32 32 DialogOuterProps, 33 33 } from '#/components/Dialog/types' 34 34 import {createInput} from '#/components/forms/TextField' 35 + import {FullWindowOverlay} from '#/components/FullWindowOverlay' 35 36 import {Portal} from '#/components/Portal' 36 37 37 38 export {useDialogContext, useDialogControl} from '#/components/Dialog/context' ··· 170 171 return ( 171 172 isOpen && ( 172 173 <Portal> 173 - <View 174 - // iOS 175 - accessibilityViewIsModal 176 - // Android 177 - importantForAccessibility="yes" 178 - style={[a.absolute, a.inset_0]} 179 - testID={testID} 180 - onTouchMove={() => Keyboard.dismiss()}> 181 - <BottomSheet 182 - enableDynamicSizing={!hasSnapPoints} 183 - enablePanDownToClose 184 - keyboardBehavior="interactive" 185 - android_keyboardInputMode="adjustResize" 186 - keyboardBlurBehavior="restore" 187 - topInset={insets.top} 188 - {...sheetOptions} 189 - snapPoints={sheetOptions.snapPoints || ['100%']} 190 - ref={sheet} 191 - index={openIndex} 192 - backgroundStyle={{backgroundColor: 'transparent'}} 193 - backdropComponent={Backdrop} 194 - handleIndicatorStyle={{backgroundColor: t.palette.primary_500}} 195 - handleStyle={{display: 'none'}} 196 - onClose={onCloseAnimationComplete}> 197 - <Context.Provider value={context}> 198 - <View 199 - style={[ 200 - a.absolute, 201 - a.inset_0, 202 - t.atoms.bg, 203 - { 204 - borderTopLeftRadius: 40, 205 - borderTopRightRadius: 40, 206 - height: Dimensions.get('window').height * 2, 207 - }, 208 - ]} 209 - /> 210 - {children} 211 - </Context.Provider> 212 - </BottomSheet> 213 - </View> 174 + <FullWindowOverlay> 175 + <View 176 + // iOS 177 + accessibilityViewIsModal 178 + // Android 179 + importantForAccessibility="yes" 180 + style={[a.absolute, a.inset_0]} 181 + testID={testID} 182 + onTouchMove={() => Keyboard.dismiss()}> 183 + <BottomSheet 184 + enableDynamicSizing={!hasSnapPoints} 185 + enablePanDownToClose 186 + keyboardBehavior="interactive" 187 + android_keyboardInputMode="adjustResize" 188 + keyboardBlurBehavior="restore" 189 + topInset={insets.top} 190 + {...sheetOptions} 191 + snapPoints={sheetOptions.snapPoints || ['100%']} 192 + ref={sheet} 193 + index={openIndex} 194 + backgroundStyle={{backgroundColor: 'transparent'}} 195 + backdropComponent={Backdrop} 196 + handleIndicatorStyle={{backgroundColor: t.palette.primary_500}} 197 + handleStyle={{display: 'none'}} 198 + onClose={onCloseAnimationComplete}> 199 + <Context.Provider value={context}> 200 + <View 201 + style={[ 202 + a.absolute, 203 + a.inset_0, 204 + t.atoms.bg, 205 + { 206 + borderTopLeftRadius: 40, 207 + borderTopRightRadius: 40, 208 + height: Dimensions.get('window').height * 2, 209 + }, 210 + ]} 211 + /> 212 + {children} 213 + </Context.Provider> 214 + </BottomSheet> 215 + </View> 216 + </FullWindowOverlay> 214 217 </Portal> 215 218 ) 216 219 )
+1
src/components/FullWindowOverlay.ios.tsx
··· 1 + export {FullWindowOverlay} from 'react-native-screens'
+1
src/components/FullWindowOverlay.tsx
··· 1 + export {Fragment as FullWindowOverlay} from 'react'
+117 -109
src/view/com/composer/Composer.tsx
··· 181 181 borderColor: interpolateColor( 182 182 hasScrolled.value, 183 183 [0, 1], 184 - [ 185 - 'transparent', 186 - isWeb 187 - ? t.atoms.border_contrast_low.borderColor 188 - : t.atoms.border_contrast_high.borderColor, 189 - ], 184 + ['transparent', t.atoms.border_contrast_medium.borderColor], 190 185 ), 191 186 } 192 187 }) ··· 405 400 <KeyboardAvoidingView 406 401 testID="composePostView" 407 402 behavior="padding" 408 - style={s.flex1} 409 - keyboardVerticalOffset={replyTo ? 60 : isAndroid ? 120 : 100}> 410 - <View style={[s.flex1, viewStyles]} aria-modal accessibilityViewIsModal> 403 + style={a.flex_1} 404 + keyboardVerticalOffset={replyTo ? 120 : isAndroid ? 180 : 150}> 405 + <View 406 + style={[a.flex_1, viewStyles]} 407 + aria-modal 408 + accessibilityViewIsModal> 411 409 <Animated.View 412 410 style={[ 413 411 styles.topbar, 414 412 topBarAnimatedStyle, 415 413 isWeb && isTabletOrDesktop && styles.topbarDesktop, 416 414 ]}> 417 - <TouchableOpacity 418 - testID="composerDiscardButton" 419 - onPress={onPressCancel} 420 - onAccessibilityEscape={onPressCancel} 421 - accessibilityRole="button" 422 - accessibilityLabel={_(msg`Cancel`)} 423 - accessibilityHint={_( 424 - msg`Closes post composer and discards post draft`, 415 + <View style={styles.topbarInner}> 416 + <TouchableOpacity 417 + testID="composerDiscardButton" 418 + onPress={onPressCancel} 419 + onAccessibilityEscape={onPressCancel} 420 + accessibilityRole="button" 421 + accessibilityLabel={_(msg`Cancel`)} 422 + accessibilityHint={_( 423 + msg`Closes post composer and discards post draft`, 424 + )} 425 + hitSlop={HITSLOP_10}> 426 + <Text style={[pal.link, s.f18]}> 427 + <Trans>Cancel</Trans> 428 + </Text> 429 + </TouchableOpacity> 430 + <View style={a.flex_1} /> 431 + {isProcessing ? ( 432 + <> 433 + <Text style={pal.textLight}>{processingState}</Text> 434 + <View style={styles.postBtn}> 435 + <ActivityIndicator /> 436 + </View> 437 + </> 438 + ) : ( 439 + <> 440 + <LabelsBtn 441 + labels={labels} 442 + onChange={setLabels} 443 + hasMedia={hasMedia} 444 + /> 445 + {canPost ? ( 446 + <TouchableOpacity 447 + testID="composerPublishBtn" 448 + onPress={onPressPublish} 449 + accessibilityRole="button" 450 + accessibilityLabel={ 451 + replyTo ? _(msg`Publish reply`) : _(msg`Publish post`) 452 + } 453 + accessibilityHint=""> 454 + <LinearGradient 455 + colors={[ 456 + gradients.blueLight.start, 457 + gradients.blueLight.end, 458 + ]} 459 + start={{x: 0, y: 0}} 460 + end={{x: 1, y: 1}} 461 + style={styles.postBtn}> 462 + <Text style={[s.white, s.f16, s.bold]}> 463 + {replyTo ? ( 464 + <Trans context="action">Reply</Trans> 465 + ) : ( 466 + <Trans context="action">Post</Trans> 467 + )} 468 + </Text> 469 + </LinearGradient> 470 + </TouchableOpacity> 471 + ) : ( 472 + <View style={[styles.postBtn, pal.btn]}> 473 + <Text style={[pal.textLight, s.f16, s.bold]}> 474 + <Trans context="action">Post</Trans> 475 + </Text> 476 + </View> 477 + )} 478 + </> 425 479 )} 426 - hitSlop={HITSLOP_10}> 427 - <Text style={[pal.link, s.f18]}> 428 - <Trans>Cancel</Trans> 429 - </Text> 430 - </TouchableOpacity> 431 - <View style={s.flex1} /> 432 - {isProcessing ? ( 433 - <> 434 - <Text style={pal.textLight}>{processingState}</Text> 435 - <View style={styles.postBtn}> 436 - <ActivityIndicator /> 480 + </View> 481 + 482 + {isAltTextRequiredAndMissing && ( 483 + <View style={[styles.reminderLine, pal.viewLight]}> 484 + <View style={styles.errorIcon}> 485 + <FontAwesomeIcon 486 + icon="exclamation" 487 + style={{color: colors.red4}} 488 + size={10} 489 + /> 437 490 </View> 438 - </> 439 - ) : ( 440 - <> 441 - <LabelsBtn 442 - labels={labels} 443 - onChange={setLabels} 444 - hasMedia={hasMedia} 445 - /> 446 - {canPost ? ( 447 - <TouchableOpacity 448 - testID="composerPublishBtn" 449 - onPress={onPressPublish} 450 - accessibilityRole="button" 451 - accessibilityLabel={ 452 - replyTo ? _(msg`Publish reply`) : _(msg`Publish post`) 453 - } 454 - accessibilityHint=""> 455 - <LinearGradient 456 - colors={[ 457 - gradients.blueLight.start, 458 - gradients.blueLight.end, 459 - ]} 460 - start={{x: 0, y: 0}} 461 - end={{x: 1, y: 1}} 462 - style={styles.postBtn}> 463 - <Text style={[s.white, s.f16, s.bold]}> 464 - {replyTo ? ( 465 - <Trans context="action">Reply</Trans> 466 - ) : ( 467 - <Trans context="action">Post</Trans> 468 - )} 469 - </Text> 470 - </LinearGradient> 471 - </TouchableOpacity> 472 - ) : ( 473 - <View style={[styles.postBtn, pal.btn]}> 474 - <Text style={[pal.textLight, s.f16, s.bold]}> 475 - <Trans context="action">Post</Trans> 476 - </Text> 477 - </View> 478 - )} 479 - </> 491 + <Text style={[pal.text, a.flex_1]}> 492 + <Trans>One or more images is missing alt text.</Trans> 493 + </Text> 494 + </View> 495 + )} 496 + {error !== '' && ( 497 + <View style={styles.errorLine}> 498 + <View style={styles.errorIcon}> 499 + <FontAwesomeIcon 500 + icon="exclamation" 501 + style={{color: colors.red4}} 502 + size={10} 503 + /> 504 + </View> 505 + <Text style={[s.red4, a.flex_1]}>{error}</Text> 506 + </View> 480 507 )} 481 508 </Animated.View> 482 - {isAltTextRequiredAndMissing && ( 483 - <View style={[styles.reminderLine, pal.viewLight]}> 484 - <View style={styles.errorIcon}> 485 - <FontAwesomeIcon 486 - icon="exclamation" 487 - style={{color: colors.red4}} 488 - size={10} 489 - /> 490 - </View> 491 - <Text style={[pal.text, s.flex1]}> 492 - <Trans>One or more images is missing alt text.</Trans> 493 - </Text> 494 - </View> 495 - )} 496 - {error !== '' && ( 497 - <View style={styles.errorLine}> 498 - <View style={styles.errorIcon}> 499 - <FontAwesomeIcon 500 - icon="exclamation" 501 - style={{color: colors.red4}} 502 - size={10} 503 - /> 504 - </View> 505 - <Text style={[s.red4, s.flex1]}>{error}</Text> 506 - </View> 507 - )} 508 509 <Animated.ScrollView 509 510 onScroll={scrollHandler} 510 511 style={styles.scrollView} ··· 576 577 {replyTo ? null : ( 577 578 <ThreadgateBtn threadgate={threadgate} onChange={setThreadgate} /> 578 579 )} 579 - <View style={[pal.border, styles.bottomBar]}> 580 + <View 581 + style={[ 582 + t.atoms.bg, 583 + t.atoms.border_contrast_medium, 584 + styles.bottomBar, 585 + ]}> 580 586 <View style={[a.flex_row, a.align_center, a.gap_xs]}> 581 587 <SelectPhotoBtn gallery={gallery} disabled={!canSelectImages} /> 582 588 <OpenCameraBtn gallery={gallery} disabled={!canSelectImages} /> ··· 598 604 </Button> 599 605 ) : null} 600 606 </View> 601 - <View style={s.flex1} /> 607 + <View style={a.flex_1} /> 602 608 <SelectLangBtn /> 603 609 <CharProgress count={graphemeLength} /> 604 610 </View> ··· 621 627 622 628 const styles = StyleSheet.create({ 623 629 topbar: { 624 - flexDirection: 'row', 625 - alignItems: 'center', 626 - marginHorizontal: 16, 627 - height: 54, 628 - gap: 4, 629 630 borderBottomWidth: StyleSheet.hairlineWidth, 630 631 }, 631 632 topbarDesktop: { ··· 633 634 paddingBottom: 10, 634 635 height: 50, 635 636 }, 637 + topbarInner: { 638 + flexDirection: 'row', 639 + alignItems: 'center', 640 + paddingHorizontal: 16, 641 + height: 54, 642 + gap: 4, 643 + }, 636 644 postBtn: { 637 645 borderRadius: 20, 638 646 paddingHorizontal: 20, ··· 643 651 flexDirection: 'row', 644 652 backgroundColor: colors.red1, 645 653 borderRadius: 6, 646 - marginHorizontal: 15, 654 + marginHorizontal: 16, 647 655 paddingHorizontal: 8, 648 656 paddingVertical: 6, 649 - marginVertical: 6, 657 + marginBottom: 8, 650 658 }, 651 659 reminderLine: { 652 660 flexDirection: 'row', 653 661 alignItems: 'center', 654 662 borderRadius: 6, 655 - marginHorizontal: 15, 663 + marginHorizontal: 16, 656 664 paddingHorizontal: 8, 657 665 paddingVertical: 6, 658 - marginBottom: 6, 666 + marginBottom: 8, 659 667 }, 660 668 errorIcon: { 661 669 borderWidth: hairlineWidth, ··· 690 698 bottomBar: { 691 699 flexDirection: 'row', 692 700 paddingVertical: 4, 693 - paddingLeft: 15, 694 - paddingRight: 20, 701 + paddingLeft: 8, 702 + paddingRight: 16, 695 703 alignItems: 'center', 696 704 borderTopWidth: hairlineWidth, 697 705 },
+1 -5
src/view/com/composer/ComposerReplyTo.tsx
··· 10 10 import {msg} from '@lingui/macro' 11 11 import {useLingui} from '@lingui/react' 12 12 13 - import {isWeb} from '#/platform/detection' 14 13 import {sanitizeDisplayName} from 'lib/strings/display-names' 15 14 import {sanitizeHandle} from 'lib/strings/handles' 16 15 import {ComposerOptsPostRef} from 'state/shell/composer' ··· 76 75 77 76 return ( 78 77 <Pressable 79 - style={[ 80 - isWeb ? t.atoms.border_contrast_low : t.atoms.border_contrast_high, 81 - styles.replyToLayout, 82 - ]} 78 + style={[t.atoms.border_contrast_medium, styles.replyToLayout]} 83 79 onPress={onPress} 84 80 accessibilityRole="button" 85 81 accessibilityLabel={_(
+3 -2
src/view/com/composer/threadgate/ThreadgateBtn.tsx
··· 7 7 import {useModalControls} from '#/state/modals' 8 8 import {ThreadgateSetting} from '#/state/queries/threadgate' 9 9 import {useAnalytics} from 'lib/analytics/analytics' 10 - import {atoms as a} from '#/alf' 10 + import {atoms as a, useTheme} from '#/alf' 11 11 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 12 12 import {CircleBanSign_Stroke2_Corner0_Rounded as CircleBanSign} from '#/components/icons/CircleBanSign' 13 13 import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe' ··· 22 22 }) { 23 23 const {track} = useAnalytics() 24 24 const {_} = useLingui() 25 + const t = useTheme() 25 26 const {openModal} = useModalControls() 26 27 27 28 const onPress = () => { ··· 45 46 : _(msg`Some people can reply`) 46 47 47 48 return ( 48 - <View style={[a.flex_row, a.pb_sm, a.px_md]}> 49 + <View style={[a.flex_row, a.py_xs, a.px_sm, t.atoms.bg]}> 49 50 <Button 50 51 variant="solid" 51 52 color="secondary"
+23 -18
src/view/com/modals/Modal.tsx
··· 1 - import React, {useEffect, useRef} from 'react' 1 + import React, {Fragment, useEffect, useRef} from 'react' 2 2 import {StyleSheet} from 'react-native' 3 3 import {SafeAreaView} from 'react-native-safe-area-context' 4 4 import BottomSheet from '@discord/bottom-sheet/src' 5 5 6 6 import {useModalControls, useModals} from '#/state/modals' 7 7 import {usePalette} from 'lib/hooks/usePalette' 8 + import {FullWindowOverlay} from '#/components/FullWindowOverlay' 8 9 import {KeyboardPadding} from '#/components/KeyboardPadding' 9 10 import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' 10 11 import * as AddAppPassword from './AddAppPasswords' ··· 127 128 ) 128 129 } 129 130 131 + const Container = activeModal ? FullWindowOverlay : Fragment 132 + 130 133 return ( 131 - <BottomSheet 132 - ref={bottomSheetRef} 133 - snapPoints={snapPoints} 134 - handleHeight={HANDLE_HEIGHT} 135 - index={isModalActive ? 0 : -1} 136 - enablePanDownToClose 137 - android_keyboardInputMode="adjustResize" 138 - keyboardBlurBehavior="restore" 139 - backdropComponent={ 140 - isModalActive ? createCustomBackdrop(onClose) : undefined 141 - } 142 - handleIndicatorStyle={{backgroundColor: pal.text.color}} 143 - handleStyle={[styles.handle, pal.view]} 144 - onChange={onBottomSheetChange}> 145 - {element} 146 - <KeyboardPadding /> 147 - </BottomSheet> 134 + <Container> 135 + <BottomSheet 136 + ref={bottomSheetRef} 137 + snapPoints={snapPoints} 138 + handleHeight={HANDLE_HEIGHT} 139 + index={isModalActive ? 0 : -1} 140 + enablePanDownToClose 141 + android_keyboardInputMode="adjustResize" 142 + keyboardBlurBehavior="restore" 143 + backdropComponent={ 144 + isModalActive ? createCustomBackdrop(onClose) : undefined 145 + } 146 + handleIndicatorStyle={{backgroundColor: pal.text.color}} 147 + handleStyle={[styles.handle, pal.view]} 148 + onChange={onBottomSheetChange}> 149 + {element} 150 + <KeyboardPadding /> 151 + </BottomSheet> 152 + </Container> 148 153 ) 149 154 } 150 155
+11 -10
src/view/com/modals/Threadgate.tsx
··· 7 7 View, 8 8 ViewStyle, 9 9 } from 'react-native' 10 - import {Text} from '../util/text/Text' 11 - import {s, colors} from 'lib/styles' 10 + import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 11 + import {msg, Trans} from '@lingui/macro' 12 + import {useLingui} from '@lingui/react' 13 + import isEqual from 'lodash.isequal' 14 + 15 + import {useModalControls} from '#/state/modals' 16 + import {useMyListsQuery} from '#/state/queries/my-lists' 17 + import {ThreadgateSetting} from '#/state/queries/threadgate' 12 18 import {usePalette} from 'lib/hooks/usePalette' 19 + import {colors, s} from 'lib/styles' 13 20 import {isWeb} from 'platform/detection' 14 21 import {ScrollView} from 'view/com/modals/util' 15 - import {Trans, msg} from '@lingui/macro' 16 - import {useLingui} from '@lingui/react' 17 - import {useModalControls} from '#/state/modals' 18 - import {ThreadgateSetting} from '#/state/queries/threadgate' 19 - import {useMyListsQuery} from '#/state/queries/my-lists' 20 - import isEqual from 'lodash.isequal' 21 - import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 22 + import {Text} from '../util/text/Text' 22 23 23 24 export const snapPoints = ['60%'] 24 25 ··· 155 156 accessibilityLabel={label} 156 157 accessibilityHint="" 157 158 style={[styles.selectable, pal.border, pal.view, style]}> 158 - <Text type="xl" style={[pal.text]}> 159 + <Text type="lg" style={[pal.text]}> 159 160 {label} 160 161 </Text> 161 162 {isSelected ? (
+2 -2
src/view/com/util/BottomSheetCustomBackdrop.tsx
··· 1 1 import React, {useMemo} from 'react' 2 2 import {TouchableWithoutFeedback} from 'react-native' 3 3 import Animated, { 4 - Extrapolate, 4 + Extrapolation, 5 5 interpolate, 6 6 useAnimatedStyle, 7 7 } from 'react-native-reanimated' ··· 21 21 animatedIndex.value, // current snap index 22 22 [-1, 0], // input range 23 23 [0, 0.5], // output range 24 - Extrapolate.CLAMP, 24 + Extrapolation.CLAMP, 25 25 ), 26 26 })) 27 27
+18 -17
src/view/com/util/forms/DropdownButton.tsx
··· 2 2 import { 3 3 Dimensions, 4 4 GestureResponderEvent, 5 - Platform, 6 5 StyleProp, 7 6 StyleSheet, 8 7 TouchableOpacity, ··· 11 10 View, 12 11 ViewStyle, 13 12 } from 'react-native' 13 + import Animated, {FadeIn, FadeInDown, FadeInUp} from 'react-native-reanimated' 14 14 import RootSiblings from 'react-native-root-siblings' 15 - import {FullWindowOverlay} from 'react-native-screens' 16 15 import {IconProp} from '@fortawesome/fontawesome-svg-core' 17 16 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 18 17 import {msg} from '@lingui/macro' ··· 23 22 import {colors} from 'lib/styles' 24 23 import {useTheme} from 'lib/ThemeContext' 25 24 import {isWeb} from 'platform/detection' 25 + import {native} from '#/alf' 26 + import {FullWindowOverlay} from '#/components/FullWindowOverlay' 26 27 import {Text} from '../text/Text' 27 28 import {Button, ButtonType} from './Button' 28 29 ··· 127 128 pageY, 128 129 menuWidth, 129 130 items.filter(v => !!v) as DropdownItem[], 131 + openUpwards, 130 132 ) 131 133 }, 132 134 ) ··· 181 183 pageY: number, 182 184 width: number, 183 185 items: DropdownItem[], 186 + opensUpwards = false, 184 187 ): RootSiblings { 185 188 const onPressItem = (index: number) => { 186 189 sibling.destroy() ··· 200 203 width={width} 201 204 items={items} 202 205 onPressItem={onPressItem} 206 + openUpwards={opensUpwards} 203 207 /> 204 208 ), 205 209 ) ··· 214 218 width: number 215 219 items: DropdownItem[] 216 220 onPressItem: (index: number) => void 221 + openUpwards: boolean 217 222 } 218 223 219 224 const DropdownItems = ({ ··· 224 229 width, 225 230 items, 226 231 onPressItem, 232 + openUpwards, 227 233 }: DropDownItemProps) => { 228 234 const pal = usePalette('default') 229 235 const theme = useTheme() ··· 242 248 // - (On mobile) be buttons by default, accept `label` and `nativeID` 243 249 // props, and always have an explicit label 244 250 return ( 245 - <Wrapper> 251 + <FullWindowOverlay> 246 252 {/* This TouchableWithoutFeedback renders the background so if the user clicks outside, the dropdown closes */} 247 253 <TouchableWithoutFeedback 248 254 onPress={onOuterPress} 249 255 accessibilityLabel={_(msg`Toggle dropdown`)} 250 256 accessibilityHint=""> 251 - <View 257 + <Animated.View 258 + entering={FadeIn} 252 259 style={[ 253 260 styles.bg, 254 261 // On web we need to adjust the top and bottom relative to the scroll position ··· 264 271 ]} 265 272 /> 266 273 </TouchableWithoutFeedback> 267 - <View 274 + <Animated.View 275 + entering={native( 276 + openUpwards ? FadeInDown.springify(1000) : FadeInUp.springify(1000), 277 + )} 268 278 style={[ 269 279 styles.menu, 270 280 {left: x, top: y, width}, ··· 306 316 } 307 317 return null 308 318 })} 309 - </View> 310 - </Wrapper> 319 + </Animated.View> 320 + </FullWindowOverlay> 311 321 ) 312 322 } 313 323 314 - // on iOS, due to formSheet presentation style, we need to render the overlay 315 - // as a full screen overlay 316 - const Wrapper = Platform.select({ 317 - ios: FullWindowOverlay, 318 - default: ({children}) => <>{children}</>, 319 - }) 320 - 321 324 function isSep(item: DropdownItem): item is DropdownItemSeparator { 322 325 return 'sep' in item && item.sep 323 326 } ··· 333 336 position: 'absolute', 334 337 left: 0, 335 338 width: '100%', 336 - backgroundColor: '#000', 337 - opacity: 0.1, 339 + backgroundColor: 'rgba(0, 0, 0, 0.1)', 338 340 }, 339 341 menu: { 340 342 position: 'absolute', 341 343 backgroundColor: '#fff', 342 344 borderRadius: 14, 343 - opacity: 1, 344 345 paddingVertical: 6, 345 346 }, 346 347 menuItem: {
+47 -16
src/view/shell/Composer.tsx
··· 1 1 import React, {useLayoutEffect} from 'react' 2 2 import {Modal, View} from 'react-native' 3 + import {GestureHandlerRootView} from 'react-native-gesture-handler' 4 + import {RootSiblingParent} from 'react-native-root-siblings' 3 5 import {StatusBar} from 'expo-status-bar' 4 6 import * as SystemUI from 'expo-system-ui' 5 7 import {observer} from 'mobx-react-lite' ··· 34 36 animationType="slide" 35 37 onRequestClose={() => ref.current?.onPressCancel()}> 36 38 <View style={[t.atoms.bg, a.flex_1]}> 37 - <LegacyModalProvider> 38 - <PortalProvider> 39 - <ComposePost 40 - cancelRef={ref} 41 - replyTo={state?.replyTo} 42 - onPost={state?.onPost} 43 - quote={state?.quote} 44 - mention={state?.mention} 45 - text={state?.text} 46 - imageUris={state?.imageUris} 47 - /> 48 - <LegacyModalsContainer /> 49 - <PortalOutlet /> 50 - </PortalProvider> 51 - </LegacyModalProvider> 52 - {isIOS && <IOSModalBackground active={open} />} 39 + <Providers open={open}> 40 + <ComposePost 41 + cancelRef={ref} 42 + replyTo={state?.replyTo} 43 + onPost={state?.onPost} 44 + quote={state?.quote} 45 + mention={state?.mention} 46 + text={state?.text} 47 + imageUris={state?.imageUris} 48 + /> 49 + </Providers> 53 50 </View> 54 51 </Modal> 55 52 ) 56 53 }) 54 + 55 + function Providers({ 56 + children, 57 + open, 58 + }: { 59 + children: React.ReactNode 60 + open: boolean 61 + }) { 62 + // on iOS, it's a native formSheet. We use FullWindowOverlay to make 63 + // the dialogs appear over it 64 + if (isIOS) { 65 + return ( 66 + <> 67 + {children} 68 + <IOSModalBackground active={open} /> 69 + </> 70 + ) 71 + } else { 72 + // on Android we just nest the dialogs within it 73 + return ( 74 + <GestureHandlerRootView style={a.flex_1}> 75 + <RootSiblingParent> 76 + <LegacyModalProvider> 77 + <PortalProvider> 78 + {children} 79 + <LegacyModalsContainer /> 80 + <PortalOutlet /> 81 + </PortalProvider> 82 + </LegacyModalProvider> 83 + </RootSiblingParent> 84 + </GestureHandlerRootView> 85 + ) 86 + } 87 + } 57 88 58 89 // Generally, the backdrop of the app is the theme color, but when this is open 59 90 // we want it to be black due to the modal being a form sheet.