[Sheets] [Pt. 8] Allow nesting in other sheets or native modals (#5567)

This commit is contained in:
Hailey
2024-10-02 21:26:58 -07:00
committed by GitHub
parent ecf7215a34
commit c49182009a
11 changed files with 97 additions and 63 deletions
+1 -1
View File
@@ -68,7 +68,7 @@
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-native-fontawesome": "^0.3.2",
"@haileyok/bluesky-bottom-sheet": "^0.1.1-alpha.8",
"@haileyok/bluesky-bottom-sheet": "^0.1.1-alpha.9",
"@haileyok/bluesky-video": "0.1.10",
"@lingui/react": "^4.5.0",
"@mattermost/react-native-paste-input": "^0.7.1",
+41 -20
View File
@@ -1,12 +1,13 @@
import React, {useImperativeHandle} from 'react'
import {StyleProp, TextInput, View, ViewStyle} from 'react-native'
import {GestureHandlerRootView, ScrollView} from 'react-native-gesture-handler'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {BlueskyBottomSheetView} from '@haileyok/bluesky-bottom-sheet'
import {logger} from '#/logger'
import {isIOS} from '#/platform/detection'
import {useDialogStateControlContext} from '#/state/dialogs'
import {List, ListMethods, ListProps} from '#/view/com/util/List'
import {ScrollView} from '#/view/com/util/Views'
import {atoms as a, flatten, useTheme} from '#/alf'
import {Context} from '#/components/Dialog/context'
import {
@@ -29,6 +30,26 @@ export function Outer({
onClose,
nativeOptions,
testID,
}: React.PropsWithChildren<DialogOuterProps>) {
return (
<Portal>
<OuterWithoutPortal
control={control}
onClose={onClose}
nativeOptions={nativeOptions}
testID={testID}>
{children}
</OuterWithoutPortal>
</Portal>
)
}
export function OuterWithoutPortal({
children,
control,
onClose,
nativeOptions,
testID,
}: React.PropsWithChildren<DialogOuterProps>) {
const t = useTheme()
const ref = React.useRef<BlueskyBottomSheetView>(null)
@@ -84,26 +105,26 @@ export function Outer({
const context = React.useMemo(() => ({close, insideDialog: true}), [close])
const Wrapper = isIOS ? View : GestureHandlerRootView
return (
<Portal>
<Context.Provider value={context}>
<BlueskyBottomSheetView
ref={ref}
topInset={30}
bottomInset={insets.bottom}
onStateChange={e => {
if (e.nativeEvent.state === 'closed') {
onCloseAnimationComplete()
}
}}
cornerRadius={20}
{...nativeOptions}>
<View testID={testID} style={[t.atoms.bg]}>
{children}
</View>
</BlueskyBottomSheetView>
</Context.Provider>
</Portal>
<Context.Provider value={context}>
<BlueskyBottomSheetView
ref={ref}
topInset={30}
bottomInset={insets.bottom}
onStateChange={e => {
if (e.nativeEvent.state === 'closed') {
onCloseAnimationComplete()
}
}}
cornerRadius={20}
{...nativeOptions}>
<Wrapper testID={testID} style={[t.atoms.bg]}>
{children}
</Wrapper>
</BlueskyBottomSheetView>
</Context.Provider>
)
}
+1
View File
@@ -103,6 +103,7 @@ export function Outer({
const context = React.useMemo(
() => ({
close,
insideDialog: true,
}),
[close],
)
+2 -3
View File
@@ -23,7 +23,6 @@ import {shouldClickOpenNewTab} from '#/platform/urls'
import {useModalControls} from '#/state/modals'
import {useOpenLink} from '#/state/preferences/in-app-browser'
import {atoms as a, flatten, TextStyleProp, useTheme, web} from '#/alf'
import {BottomSheetButton} from '#/components/BottomSheetButton'
import {Button, ButtonProps} from '#/components/Button'
import {useInteractionState} from '#/components/hooks/useInteractionState'
import {Text, TextProps} from '#/components/Typography'
@@ -258,7 +257,7 @@ export function BottomSheetLink({
})
return (
<BottomSheetButton
<Button
{...rest}
style={[a.justify_start, flatten(rest.style)]}
role="link"
@@ -277,7 +276,7 @@ export function BottomSheetLink({
},
})}>
{children}
</BottomSheetButton>
</Button>
)
}
+17 -6
View File
@@ -3,8 +3,9 @@ import {GestureResponderEvent, View} from 'react-native'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {isNative} from '#/platform/detection'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonColor, ButtonProps, ButtonText} from '#/components/Button'
import {Button, ButtonColor, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {Text} from '#/components/Typography'
@@ -25,9 +26,11 @@ export function Outer({
children,
control,
testID,
withoutPortal,
}: React.PropsWithChildren<{
control: Dialog.DialogControlProps
testID?: string
withoutPortal?: boolean
}>) {
const {gtMobile} = useBreakpoints()
const titleId = React.useId()
@@ -38,8 +41,11 @@ export function Outer({
[titleId, descriptionId],
)
const Wrapper =
withoutPortal && isNative ? Dialog.OuterWithoutPortal : Dialog.Outer
return (
<Dialog.Outer control={control} testID={testID}>
<Wrapper control={control} testID={testID}>
<Context.Provider value={context}>
<Dialog.ScrollableInner
accessibilityLabelledBy={titleId}
@@ -50,7 +56,7 @@ export function Outer({
{children}
</Dialog.ScrollableInner>
</Context.Provider>
</Dialog.Outer>
</Wrapper>
)
}
@@ -139,7 +145,7 @@ export function Action({
* Note: The dialog will close automatically when the action is pressed, you
* should NOT close the dialog as a side effect of this method.
*/
onPress: ButtonProps['onPress']
onPress: (e: GestureResponderEvent) => void
color?: ButtonColor
/**
* Optional i18n string. If undefined, it will default to "Confirm".
@@ -179,6 +185,7 @@ export function Basic({
onConfirm,
confirmButtonColor,
showCancel = true,
withoutPortal,
}: React.PropsWithChildren<{
control: Dialog.DialogOuterProps['control']
title: string
@@ -192,12 +199,16 @@ export function Basic({
* Note: The dialog will close automatically when the action is pressed, you
* should NOT close the dialog as a side effect of this method.
*/
onConfirm: ButtonProps['onPress']
onConfirm: (e: GestureResponderEvent) => void
confirmButtonColor?: ButtonColor
showCancel?: boolean
withoutPortal?: boolean
}>) {
return (
<Outer control={control} testID="confirmModal">
<Outer
control={control}
testID="confirmModal"
withoutPortal={withoutPortal}>
<TitleText>{title}</TitleText>
<DescriptionText>{description}</DescriptionText>
<Actions>
@@ -6,8 +6,7 @@ import {useLingui} from '@lingui/react'
import {getLabelingServiceTitle} from '#/lib/moderation'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {BottomSheetButton} from '#/components/BottomSheetButton'
import {useButtonContext} from '#/components/Button'
import {Button, useButtonContext} from '#/components/Button'
import {Divider} from '#/components/Divider'
import * as LabelingServiceCard from '#/components/LabelingServiceCard'
import {Text} from '#/components/Typography'
@@ -39,12 +38,12 @@ export function SelectLabelerView({
<View style={[a.gap_sm]}>
{props.labelers.map(labeler => {
return (
<BottomSheetButton
<Button
key={labeler.creator.did}
label={_(msg`Send report to ${labeler.creator.displayName}`)}
onPress={() => props.onSelectLabeler(labeler.creator.did)}>
<LabelerButton labeler={labeler} />
</BottomSheetButton>
</Button>
)
})}
</View>
+2 -1
View File
@@ -1,5 +1,6 @@
import React from 'react'
import {Pressable, ScrollView, View} from 'react-native'
import {Pressable, View} from 'react-native'
import {ScrollView} from 'react-native-gesture-handler'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
@@ -13,9 +13,8 @@ import {logger} from '#/logger'
import {useAgent, useSession} from '#/state/session'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {BottomSheetButton} from '#/components/BottomSheetButton'
import {BottomSheetInlineLinkText} from '#/components/BottomSheetLink'
import {ButtonIcon, ButtonText} from '#/components/Button'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {InlineLinkText} from '#/components/Link'
import {Text} from '#/components/Typography'
@@ -141,7 +140,7 @@ function Label({
</View>
{!isSelfLabel && (
<View>
<BottomSheetButton
<Button
variant="solid"
color="secondary"
size="small"
@@ -150,7 +149,7 @@ function Label({
<ButtonText>
<Trans>Appeal</Trans>
</ButtonText>
</BottomSheetButton>
</Button>
</View>
)}
</View>
@@ -279,7 +278,7 @@ function AppealForm({
? [a.flex_row, a.justify_between]
: [{flexDirection: 'column-reverse'}, a.gap_sm]
}>
<BottomSheetButton
<Button
testID="backBtn"
variant="solid"
color="secondary"
@@ -287,8 +286,8 @@ function AppealForm({
onPress={onPressBack}
label={_(msg`Back`)}>
<ButtonText>{_(msg`Back`)}</ButtonText>
</BottomSheetButton>
<BottomSheetButton
</Button>
<Button
testID="submitBtn"
variant="solid"
color="primary"
@@ -297,7 +296,7 @@ function AppealForm({
label={_(msg`Submit`)}>
<ButtonText>{_(msg`Submit`)}</ButtonText>
{isPending && <ButtonIcon icon={Loader} />}
</BottomSheetButton>
</Button>
</View>
</>
)
@@ -10,6 +10,7 @@ import {listUriToHref} from '#/lib/strings/url-helpers'
import {isNative} from '#/platform/detection'
import {useSession} from '#/state/session'
import {atoms as a, useTheme} from '#/alf'
import {BottomSheetInlineLinkText} from '#/components/BottomSheetLink'
import * as Dialog from '#/components/Dialog'
import {Divider} from '#/components/Divider'
import {InlineLinkText} from '#/components/Link'
@@ -140,23 +141,24 @@ function ModerationDetailsDialogInner({
{modcause?.type === 'label' && (
<View style={[a.pt_lg]}>
<Divider />
<Text style={[t.atoms.text, a.text_md, a.leading_snug, a.mt_lg]}>
{modcause.source.type === 'user' ? (
{modcause.source.type === 'user' ? (
<Text style={[t.atoms.text, a.text_md, a.leading_snug, a.mt_lg]}>
<Trans>This label was applied by the author.</Trans>
) : (
<Trans>
This label was applied by{' '}
<InlineLinkText
label={desc.source || _(msg`an unknown labeler`)}
to={makeProfileLink({did: modcause.label.src, handle: ''})}
onPress={() => control.close()}
style={a.text_md}>
{desc.source || _(msg`an unknown labeler`)}
</InlineLinkText>
.
</Trans>
)}
</Text>
</Text>
) : (
<>
<Text style={[t.atoms.text, a.text_md, a.leading_snug, a.mt_lg]}>
<Trans>This label was applied by </Trans>
</Text>
<BottomSheetInlineLinkText
label={desc.source || _(msg`an unknown labeler`)}
to={makeProfileLink({did: modcause.label.src, handle: ''})}
onPress={() => control.close()}
style={a.text_md}>
{desc.source || _(msg`an unknown labeler`)}
</BottomSheetInlineLinkText>
</>
)}
</View>
)}
+1
View File
@@ -861,6 +861,7 @@ export const ComposePost = ({
onConfirm={onClose}
confirmButtonCta={_(msg`Discard`)}
confirmButtonColor="negative"
withoutPortal={true}
/>
</KeyboardAvoidingView>
)
+4 -4
View File
@@ -4120,10 +4120,10 @@
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
"@haileyok/bluesky-bottom-sheet@^0.1.1-alpha.8":
version "0.1.1-alpha.8"
resolved "https://registry.yarnpkg.com/@haileyok/bluesky-bottom-sheet/-/bluesky-bottom-sheet-0.1.1-alpha.8.tgz#c5fd503cdd5556a686a1f5c0974b1527fceda900"
integrity sha512-305MSNscniLZpxd80QO4OCuMXkm+U/v/YW/x0fVQtBilVTikOOPIkiYge+kCUdryFPD3LU/GdrsQZL+y8qAiMQ==
"@haileyok/bluesky-bottom-sheet@^0.1.1-alpha.9":
version "0.1.1-alpha.9"
resolved "https://registry.yarnpkg.com/@haileyok/bluesky-bottom-sheet/-/bluesky-bottom-sheet-0.1.1-alpha.9.tgz#f23a9245d4fed5e1825222249f2ad64ec99896e6"
integrity sha512-duGQ/l20Mr/lmjS7lUu0T0QgARA/V47PrmpL7LZJMoK4IhSBHT4HMSjjOaBcSJhQg2I5/uSX3pShFzCfdGttVQ==
"@haileyok/bluesky-video@0.1.10":
version "0.1.10"